From 8404bceb0c9efd5d69de1918b3530918940a52bf Mon Sep 17 00:00:00 2001 From: yann300 Date: Fri, 5 Jun 2015 14:43:38 +0200 Subject: [PATCH 01/40] Add ScenarioExecution + ScenarioLoader --- mix/ClientModel.cpp | 231 ++++++++++++++---------- mix/ClientModel.h | 34 +++- mix/ContractCallDataEncoder.cpp | 15 +- mix/ContractCallDataEncoder.h | 4 +- mix/MachineStates.h | 1 + mix/MixClient.cpp | 17 +- mix/MixClient.h | 5 +- mix/main.cpp | 4 +- mix/qml.qrc | 4 + mix/qml/Application.qml | 21 +-- mix/qml/Block.qml | 145 +++++++++++++++ mix/qml/BlockChain.qml | 306 ++++++++++++++++++++++++++++++++ mix/qml/Debugger.qml | 84 ++------- mix/qml/MainContent.qml | 72 +++++--- mix/qml/QAddressView.qml | 32 ++-- mix/qml/ScenarioExecution.qml | 57 ++++++ mix/qml/ScenarioLoader.qml | 77 ++++++++ mix/qml/StateListModel.qml | 129 +++++++++++--- mix/qml/StructView.qml | 1 + mix/qml/TransactionDialog.qml | 14 +- mix/qml/js/ProjectModel.js | 2 + mix/qml/js/TransactionHelper.js | 3 +- 22 files changed, 996 insertions(+), 262 deletions(-) create mode 100644 mix/qml/Block.qml create mode 100644 mix/qml/BlockChain.qml create mode 100644 mix/qml/ScenarioExecution.qml create mode 100644 mix/qml/ScenarioLoader.qml diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index cad210f1b..3cd401e23 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -82,12 +82,14 @@ ClientModel::ClientModel(): qRegisterMetaType("QCallData"); qRegisterMetaType("RecordLogEntry*"); - connect(this, &ClientModel::runComplete, this, &ClientModel::showDebugger, Qt::QueuedConnection); + //connect(this, &ClientModel::runComplete, this, &ClientModel::showDebugger, Qt::QueuedConnection); m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString())); m_ethAccounts = make_shared([=](){return m_client.get();}, std::vector()); m_web3Server.reset(new Web3Server(*m_rpcConnector.get(), m_ethAccounts, std::vector(), m_client.get())); connect(m_web3Server.get(), &Web3Server::newTransaction, this, &ClientModel::onNewTransaction, Qt::DirectConnection); + + } ClientModel::~ClientModel() @@ -111,7 +113,7 @@ QString ClientModel::apiCall(QString const& _message) void ClientModel::mine() { - if (m_running || m_mining) + if (m_mining) BOOST_THROW_EXCEPTION(ExecutionStateException()); m_mining = true; emit miningStarted(); @@ -206,92 +208,131 @@ QVariantList ClientModel::gasCosts() const return res; } -void ClientModel::setupState(QVariantMap _state) +void ClientModel::setupScenario(QVariantMap _scenario) { - QVariantList stateAccounts = _state.value("accounts").toList(); - QVariantList stateContracts = _state.value("contracts").toList(); - QVariantList transactions = _state.value("transactions").toList(); + m_queueTransactions.clear(); + m_running = true; + + m_currentScenario = _scenario; + QVariantList blocks = _scenario.value("blocks").toList(); + QVariantList stateAccounts = _scenario.value("accounts").toList(); + + m_accounts.clear(); + std::vector userAccounts; + + for (auto const& b: stateAccounts) + { + QVariantMap account = b.toMap(); + Address address = {}; + if (account.contains("secret")) + { + KeyPair key(Secret(account.value("secret").toString().toStdString())); + userAccounts.push_back(key); + address = key.address(); + } + else if (account.contains("address")) + address = Address(fromHex(account.value("address").toString().toStdString())); + if (!address) + continue; + + m_accounts[address] = Account(qvariant_cast(account.value("balance"))->toU256Wei(), Account::NormalCreation); + } + m_ethAccounts->setAccounts(userAccounts); + for (auto const& b: blocks) + { + QVariantList transactions = b.toMap().value("transactions").toList(); + m_queueTransactions.push_back(transactions); + } + + m_client->resetState(m_accounts, Secret(m_currentScenario.value("miner").toMap().value("secret").toString().toStdString())); + + connect(this, &ClientModel::newBlock, this, &ClientModel::processNextBlock, Qt::QueuedConnection); + connect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution, Qt::QueuedConnection); + connect(this, &ClientModel::runStateChanged, this, &ClientModel::finalizeBlock, Qt::QueuedConnection); + processNextBlock(); +} - unordered_map accounts; - std::vector userAccounts; +void ClientModel::stopExecution() +{ + disconnect(this, &ClientModel::newBlock, this, &ClientModel::processNextBlock); + disconnect(this, &ClientModel::runStateChanged, this, &ClientModel::finalizeBlock); + disconnect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution); + m_running = false; +} - for (auto const& b: stateAccounts) - { - QVariantMap account = b.toMap(); - Address address = {}; - if (account.contains("secret")) - { - KeyPair key(Secret(account.value("secret").toString().toStdString())); - userAccounts.push_back(key); - address = key.address(); - } - else if (account.contains("address")) - address = Address(fromHex(account.value("address").toString().toStdString())); - if (!address) - continue; +void ClientModel::finalizeBlock() +{ + if (m_queueTransactions.size() > 0) + mine(); + else + { + disconnect(this, &ClientModel::newBlock, this, &ClientModel::processNextBlock); + disconnect(this, &ClientModel::runStateChanged, this, &ClientModel::finalizeBlock); + disconnect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution); + m_running = false; + emit runComplete(); + } +} - accounts[address] = Account(qvariant_cast(account.value("balance"))->toU256Wei(), Account::NormalCreation); - } - for (auto const& c: stateContracts) - { - QVariantMap contract = c.toMap(); - Address address = Address(fromHex(contract.value("address").toString().toStdString())); - Account account(qvariant_cast(contract.value("balance"))->toU256Wei(), Account::ContractConception); - bytes code = fromHex(contract.value("code").toString().toStdString()); - account.setCode(code); - QVariantMap storageMap = contract.value("storage").toMap(); - for(auto s = storageMap.cbegin(); s != storageMap.cend(); ++s) - account.setStorage(fromBigEndian(fromHex(s.key().toStdString())), fromBigEndian(fromHex(s.value().toString().toStdString()))); - accounts[address] = account; - } - vector transactionSequence; - for (auto const& t: transactions) - { - QVariantMap transaction = t.toMap(); - QString contractId = transaction.value("contractId").toString(); - QString functionId = transaction.value("functionId").toString(); - u256 gas = boost::get(qvariant_cast(transaction.value("gas"))->internalValue()); - bool gasAuto = transaction.value("gasAuto").toBool(); - u256 value = (qvariant_cast(transaction.value("value")))->toU256Wei(); - u256 gasPrice = (qvariant_cast(transaction.value("gasPrice")))->toU256Wei(); - QString sender = transaction.value("sender").toString(); - bool isContractCreation = transaction.value("isContractCreation").toBool(); - bool isFunctionCall = transaction.value("isFunctionCall").toBool(); - if (contractId.isEmpty() && m_codeModel->hasContract()) //TODO: This is to support old project files, remove later - contractId = m_codeModel->contracts().keys()[0]; - TransactionSettings transactionSettings(contractId, functionId, value, gas, gasAuto, gasPrice, Secret(sender.toStdString()), isContractCreation, isFunctionCall); - transactionSettings.parameterValues = transaction.value("parameters").toMap(); - - if (contractId == functionId || functionId == "Constructor") - transactionSettings.functionId.clear(); - - transactionSequence.push_back(transactionSettings); - } - m_ethAccounts->setAccounts(userAccounts); - executeSequence(transactionSequence, accounts, Secret(_state.value("miner").toMap().value("secret").toString().toStdString())); +void ClientModel::processNextBlock() +{ + processNextTransactions(); } -void ClientModel::executeSequence(vector const& _sequence, std::unordered_map const& _accounts, Secret const& _miner) +void ClientModel::processNextTransactions() +{ + vector transactionSequence; + for (auto const& t: m_queueTransactions.front()) + { + QVariantMap transaction = t.toMap(); + QString contractId = transaction.value("contractId").toString(); + QString functionId = transaction.value("functionId").toString(); + bool gasAuto = transaction.value("gasAuto").toBool(); + u256 gas = 0; + if (transaction.value("gas").data()) + gas = boost::get(qvariant_cast(transaction.value("gas"))->internalValue()); + else + gasAuto = true; + + u256 value = (qvariant_cast(transaction.value("value")))->toU256Wei(); + u256 gasPrice = (qvariant_cast(transaction.value("gasPrice")))->toU256Wei(); + QString sender = transaction.value("sender").toString(); + bool isContractCreation = transaction.value("isContractCreation").toBool(); + bool isFunctionCall = transaction.value("isFunctionCall").toBool(); + if (contractId.isEmpty() && m_codeModel->hasContract()) //TODO: This is to support old project files, remove later + contractId = m_codeModel->contracts().keys()[0]; + TransactionSettings transactionSettings(contractId, functionId, value, gas, gasAuto, gasPrice, Secret(sender.toStdString()), isContractCreation, isFunctionCall); + transactionSettings.parameterValues = transaction.value("parameters").toMap(); + + if (contractId == functionId || functionId == "Constructor") + transactionSettings.functionId.clear(); + + transactionSequence.push_back(transactionSettings); + } + m_queueTransactions.pop_front(); + executeSequence(transactionSequence); +} + +void ClientModel::executeSequence(vector const& _sequence) { if (m_running) { qWarning() << "Waiting for current execution to complete"; m_runFuture.waitForFinished(); } - m_running = true; emit runStarted(); - emit runStateChanged(); + //emit runStateChanged(); + - m_client->resetState(_accounts, _miner); //run sequence m_runFuture = QtConcurrent::run([=]() { try { vector
deployedContracts; - onStateReset(); + //onStateReset(); m_gasCosts.clear(); for (TransactionSettings const& transaction: _sequence) { @@ -319,12 +360,7 @@ void ClientModel::executeSequence(vector const& _sequence, break; } if (!f) - { - emit runFailed("Function '" + transaction.functionId + tr("' not found. Please check transactions or the contract code.")); - m_running = false; - emit runStateChanged(); - return; - } + emit runFailed("Function '" + transaction.functionId + tr("' not found. Please check transactions or the contract code.")); if (!transaction.functionId.isEmpty()) encoder.encode(f); for (QVariableDeclaration const* p: f->parametersList()) @@ -355,33 +391,34 @@ void ClientModel::executeSequence(vector const& _sequence, { auto contractAddressIter = m_contractAddresses.find(ctrInstance); if (contractAddressIter == m_contractAddresses.end()) - { - emit runFailed("Contract '" + transaction.contractId + tr(" not deployed.") + "' " + tr(" Cannot call ") + transaction.functionId); - m_running = false; - emit runStateChanged(); - return; - } - callAddress(contractAddressIter->second, encoder.encodedData(), transaction); + emit runFailed("Contract '" + transaction.contractId + tr(" not deployed.") + "' " + tr(" Cannot call ") + transaction.functionId); + callAddress(contractAddressIter->second, encoder.encodedData(), transaction); } m_gasCosts.append(m_client->lastExecution().gasUsed); onNewTransaction(); - } - m_running = false; - emit runComplete(); + emit runComplete(); + } } catch(boost::exception const&) { cerr << boost::current_exception_diagnostic_information(); emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information())); - } + } catch(exception const& e) { cerr << boost::current_exception_diagnostic_information(); emit runFailed(e.what()); - } - m_running = false; + } emit runStateChanged(); - }); + }); +} + +void ClientModel::executeTr(QVariantMap _tr) +{ + QVariantList trs; + trs.push_back(_tr); + m_queueTransactions.push_back(trs); + processNextTransactions(); } @@ -399,7 +436,7 @@ std::pair ClientModel::resolvePair(QString const& _contractId) QString ClientModel::resolveToken(std::pair const& _value, vector
const& _contracts) { if (_contracts.size() > 0) - return QString::fromStdString("0x" + dev::toHex(_contracts.at(_value.second).ref())); + return QString::fromStdString("0x" + dev::toHex(m_contractAddresses[_value].ref())); //dev::toHex(_contracts.at(_value.second).ref())); else return _value.first; } @@ -610,7 +647,7 @@ void ClientModel::emptyRecord() void ClientModel::debugRecord(unsigned _index) { ExecutionResult e = m_client->execution(_index); - showDebuggerForTransaction(e); + showDebuggerForTransaction(e); } Address ClientModel::deployContract(bytes const& _code, TransactionSettings const& _ctrTransaction) @@ -631,7 +668,7 @@ RecordLogEntry* ClientModel::lastBlock() const strGas << blockInfo.gasUsed; stringstream strNumber; strNumber << blockInfo.number; - RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(dev::toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str())); + RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(dev::toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str()), QString(), tr("Block"), QVariantMap()); QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership); return record; } @@ -648,7 +685,7 @@ void ClientModel::onStateReset() void ClientModel::onNewTransaction() { ExecutionResult const& tr = m_client->lastExecution(); - unsigned block = m_client->number() + 1; + unsigned block = m_client->number() + 1; unsigned recordIndex = tr.executonIndex; QString transactionIndex = tr.isCall() ? QObject::tr("Call") : QString("%1:%2").arg(block).arg(tr.transactionIndex); QString address = QString::fromStdString(toJS(tr.address)); @@ -690,6 +727,7 @@ void ClientModel::onNewTransaction() Address contractAddress = (bool)tr.address ? tr.address : tr.contractAddress; auto contractAddressIter = m_contractNames.find(contractAddress); + QVariantMap inputParameters; if (contractAddressIter != m_contractNames.end()) { CompiledContract const& compilerRes = m_codeModel->contract(contractAddressIter->second); @@ -706,11 +744,20 @@ void ClientModel::onNewTransaction() returned += "("; returned += returnValues.join(", "); returned += ")"; - } + bytes data = tr.inputParameters; + data.erase(data.begin(), data.begin() + 4); + QStringList parameters = encoder.decode(funcDef->parametersList(), data); + for (int k = 0; k < parameters.length(); ++k) + inputParameters.insert(funcDef->parametersList().at(k)->name(), parameters.at(k)); + } } } - RecordLogEntry* log = new RecordLogEntry(recordIndex, transactionIndex, contract, function, value, address, returned, tr.isCall(), RecordLogEntry::RecordType::Transaction, gasUsed); + LocalisedLogEntries logs = m_client->logs(); + QString sender = QString::fromStdString(dev::toHex(tr.sender.ref())); + QString label = contract + "." + function + "()"; + RecordLogEntry* log = new RecordLogEntry(recordIndex, transactionIndex, contract, function, value, address, returned, tr.isCall(), RecordLogEntry::RecordType::Transaction, + gasUsed, sender, label, inputParameters); QQmlEngine::setObjectOwnership(log, QQmlEngine::JavaScriptOwnership); emit newRecord(log); } diff --git a/mix/ClientModel.h b/mix/ClientModel.h index e1648b78d..503b4189f 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -30,12 +30,13 @@ #include #include #include +#include #include "MachineStates.h" namespace dev { -namespace eth { class Account; class FixedAccountHolder; } +namespace eth { class FixedAccountHolder; } namespace mix { @@ -108,6 +109,12 @@ class RecordLogEntry: public QObject Q_PROPERTY(RecordType type MEMBER m_type CONSTANT) /// Gas used Q_PROPERTY(QString gasUsed MEMBER m_gasUsed CONSTANT) + /// Sender + Q_PROPERTY(QString sender MEMBER m_sender CONSTANT) + /// label + Q_PROPERTY(QString label MEMBER m_label CONSTANT) + /// input parameters + Q_PROPERTY(QVariantMap parameters MEMBER m_inputParameters CONSTANT) public: enum RecordType @@ -118,8 +125,10 @@ public: RecordLogEntry(): m_recordIndex(0), m_call(false), m_type(RecordType::Transaction) {} - RecordLogEntry(unsigned _recordIndex, QString _transactionIndex, QString _contract, QString _function, QString _value, QString _address, QString _returned, bool _call, RecordType _type, QString _gasUsed): - m_recordIndex(_recordIndex), m_transactionIndex(_transactionIndex), m_contract(_contract), m_function(_function), m_value(_value), m_address(_address), m_returned(_returned), m_call(_call), m_type(_type), m_gasUsed(_gasUsed) {} + RecordLogEntry(unsigned _recordIndex, QString _transactionIndex, QString _contract, QString _function, QString _value, QString _address, QString _returned, bool _call, RecordType _type, QString _gasUsed, + QString _sender, QString _label, QVariantMap _inputParameters): + m_recordIndex(_recordIndex), m_transactionIndex(_transactionIndex), m_contract(_contract), m_function(_function), m_value(_value), m_address(_address), m_returned(_returned), m_call(_call), m_type(_type), m_gasUsed(_gasUsed), + m_sender(_sender), m_label(_label), m_inputParameters(_inputParameters) {} private: unsigned m_recordIndex; @@ -132,6 +141,9 @@ private: bool m_call; RecordType m_type; QString m_gasUsed; + QString m_sender; + QString m_label; + QVariantMap m_inputParameters; }; /** @@ -172,7 +184,12 @@ public: public slots: /// Setup state, run transaction sequence, show debugger for the last transaction /// @param _state JS object with state configuration - void setupState(QVariantMap _state); + //void setupState(QVariantMap _state); + /// Setup scenario, run transaction sequence, show debugger for the last transaction + /// @param _state JS object with state configuration + void setupScenario(QVariantMap _scenario); + /// Execute the given @param _tr on the curret state + void executeTr(QVariantMap _tr); /// Show the debugger for a specified record Q_INVOKABLE void debugRecord(unsigned _index); /// Show the debugger for an empty record @@ -224,7 +241,7 @@ private: RecordLogEntry* lastBlock() const; QVariantMap contractAddresses() const; QVariantList gasCosts() const; - void executeSequence(std::vector const& _sequence, std::unordered_map const& _accounts, Secret const& _miner); + void executeSequence(std::vector const& _sequence); dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings()); void callAddress(Address const& _contract, bytes const& _data, TransactionSettings const& _tr); void onNewTransaction(); @@ -235,6 +252,10 @@ private: std::pair retrieveToken(QString const& _value, std::vector
const& _contracts); std::pair resolvePair(QString const& _contractId); QVariant formatStorageValue(SolidityType const& _type, std::unordered_map const& _storage, unsigned _offset, dev::u256 const& _slot); + void processNextTransactions(); + void processNextBlock(); + void finalizeBlock(); + void stopExecution(); std::atomic m_running; std::atomic m_mining; @@ -243,12 +264,15 @@ private: std::unique_ptr m_rpcConnector; std::unique_ptr m_web3Server; std::shared_ptr m_ethAccounts; + std::unordered_map m_accounts; QList m_gasCosts; std::map, Address> m_contractAddresses; std::map m_contractNames; std::map m_stdContractAddresses; std::map m_stdContractNames; CodeModel* m_codeModel = nullptr; + QList m_queueTransactions; + QVariantMap m_currentScenario; }; } diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 07ab8dd73..70c1e6068 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -29,6 +29,7 @@ #include "QVariableDefinition.h" #include "QFunctionDefinition.h" #include "ContractCallDataEncoder.h" +using namespace std; using namespace dev; using namespace dev::solidity; using namespace dev::mix; @@ -227,6 +228,18 @@ QVariant ContractCallDataEncoder::decode(SolidityType const& _type, bytes const& BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Parameter declaration not found")); } +QStringList ContractCallDataEncoder::decode(QList const& _returnParameters, vector _value) +{ + QStringList r; + for (int k = 0; k <_returnParameters.length(); k++) + { + QVariableDeclaration* dec = static_cast(_returnParameters.at(k)); + SolidityType const& type = dec->type()->type(); + r.append(decode(type, _value.at(k)).toString()); + } + return r; +} + QStringList ContractCallDataEncoder::decode(QList const& _returnParameters, bytes _value) { bytesConstRef value(&_value); @@ -238,7 +251,7 @@ QStringList ContractCallDataEncoder::decode(QList const& value.populate(&rawParam); value = value.cropped(32); QVariableDeclaration* dec = static_cast(_returnParameters.at(k)); - SolidityType const& type = dec->type()->type(); + SolidityType const& type = dec->type()->type(); r.append(decode(type, rawParam).toString()); } return r; diff --git a/mix/ContractCallDataEncoder.h b/mix/ContractCallDataEncoder.h index 2707845ae..57b364b49 100644 --- a/mix/ContractCallDataEncoder.h +++ b/mix/ContractCallDataEncoder.h @@ -48,7 +48,9 @@ public: void encode(QVariant const& _data, SolidityType const& _type); /// Decode variable in order to be sent to QML view. QStringList decode(QList const& _dec, bytes _value); - /// Decode single variable + /// Decode @param _parameters + QStringList decode(QList const& _parameters, std::vector _value); + /// Decode single variable QVariant decode(SolidityType const& _type, bytes const& _value); /// Get all encoded data encoded by encode function. bytes encodedData(); diff --git a/mix/MachineStates.h b/mix/MachineStates.h index 2a88d83bf..ae9804f7f 100644 --- a/mix/MachineStates.h +++ b/mix/MachineStates.h @@ -83,6 +83,7 @@ namespace mix dev::u256 gasUsed; unsigned transactionIndex; unsigned executonIndex = 0; + bytes inputParameters; bool isCall() const { return transactionIndex == std::numeric_limits::max(); } bool isConstructor() const { return !isCall() && !address; } diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index e3ed2eead..fcc72db9d 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -22,6 +22,7 @@ #include "MixClient.h" #include +#include #include #include #include @@ -69,19 +70,28 @@ bytes MixBlockChain::createGenesisBlock(h256 _stateRoot) MixClient::MixClient(std::string const& _dbPath): m_dbPath(_dbPath) { - resetState(std::unordered_map()); + resetState(std::unordered_map()); } MixClient::~MixClient() { } +LocalisedLogEntries MixClient::logs() +{ + return m_watches.at(0).changes; +} + void MixClient::resetState(std::unordered_map const& _accounts, Secret const& _miner) { + WriteGuard l(x_state); Guard fl(x_filtersWatches); m_filters.clear(); m_watches.clear(); + LogFilter filter; + m_filters.insert(std::make_pair(filter.sha3(), filter)); + m_watches.insert(std::make_pair(0, ClientWatch(filter.sha3(), Reaping::Automatic))); m_stateDB = OverlayDB(); SecureTrieDB accountState(&m_stateDB); @@ -122,7 +132,7 @@ Transaction MixClient::replaceGas(Transaction const& _t, u256 const& _gas, Secre void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _call, bool _gasAuto, Secret const& _secret) { Transaction t = _gasAuto ? replaceGas(_t, m_state.gasLimitRemaining()) : _t; - // do debugging run first + // do debugging run first LastHashes lastHashes(256); lastHashes[0] = bc().numberHash(bc().number()); for (unsigned i = 1; i < 256; ++i) @@ -213,6 +223,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c }; ExecutionResult d; + d.inputParameters = t.data(); d.result = execution.executionResult(); d.machineStates = machineStates; d.executionCode = std::move(codes); @@ -227,7 +238,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c d.transactionIndex = m_state.pending().size(); d.executonIndex = m_executions.size(); - // execute on a state + // execute on a state if (!_call) { t = _gasAuto ? replaceGas(_t, d.gasUsed, _secret) : _t; diff --git a/mix/MixClient.h b/mix/MixClient.h index 4c5b51a09..852937634 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include "MachineStates.h" @@ -76,6 +77,8 @@ public: using Interface::blockInfo; // to remove warning about hiding virtual function eth::BlockInfo blockInfo() const; + dev::eth::LocalisedLogEntries logs(); + protected: /// ClientBase methods using ClientBase::asOf; @@ -91,7 +94,7 @@ private: void noteChanged(h256Set const& _filters); dev::eth::Transaction replaceGas(dev::eth::Transaction const& _t, dev::u256 const& _gas, dev::Secret const& _secret = dev::Secret()); - eth::State m_state; + eth::State m_state; eth::State m_startState; OverlayDB m_stateDB; std::unique_ptr m_bc; diff --git a/mix/main.cpp b/mix/main.cpp index 78b5261ac..b4206ec51 100644 --- a/mix/main.cpp +++ b/mix/main.cpp @@ -32,9 +32,9 @@ int main(int _argc, char* _argv[]) { try { - MixApplication::initialize(); + MixApplication::initialize(); MixApplication app(_argc, _argv); - return app.exec(); + return app.exec(); } catch (boost::exception const& _e) { diff --git a/mix/qml.qrc b/mix/qml.qrc index 784404270..0227b4efd 100644 --- a/mix/qml.qrc +++ b/mix/qml.qrc @@ -64,5 +64,9 @@ qml/js/ansi2html.js qml/js/NetworkDeployment.js qml/js/InputValidator.js + qml/Block.qml + qml/BlockChain.qml + qml/ScenarioExecution.qml + qml/ScenarioLoader.qml diff --git a/mix/qml/Application.qml b/mix/qml/Application.qml index d041f421e..509e2e178 100644 --- a/mix/qml/Application.qml +++ b/mix/qml/Application.qml @@ -128,10 +128,8 @@ ApplicationWindow { MenuSeparator {} MenuItem { action: toggleProjectNavigatorAction } MenuItem { action: showHideRightPanelAction } - MenuItem { action: toggleTransactionLogAction } MenuItem { action: toggleWebPreviewAction } MenuItem { action: toggleWebPreviewOrientationAction } - //MenuItem { action: toggleCallsInLog } } } @@ -207,14 +205,14 @@ ApplicationWindow { enabled: codeModel.hasContract && !clientModel.running } - Action { + Action { id: toggleAssemblyDebuggingAction text: qsTr("Show VM Code") shortcut: "Ctrl+Alt+V" - onTriggered: mainContent.rightPane.assemblyMode = !mainContent.rightPane.assemblyMode; - checked: mainContent.rightPane.assemblyMode; + onTriggered: mainContent.debuggerPanel.assemblyMode = !mainContent.debuggerPanel.assemblyMode; + checked: mainContent.debuggerPanel.assemblyMode; enabled: true - } + } Action { id: toggleWebPreviewAction @@ -223,16 +221,7 @@ ApplicationWindow { checkable: true checked: mainContent.webViewVisible onTriggered: mainContent.toggleWebPreview(); - } - - Action { - id: toggleTransactionLogAction - text: qsTr("Show States and Transactions") - shortcut: "Alt+1" - checkable: true - checked: mainContent.rightPane.transactionLog.visible - onTriggered: mainContent.rightPane.transactionLog.visible = !mainContent.rightPane.transactionLog.visible - } + } Action { id: toggleProjectNavigatorAction diff --git a/mix/qml/Block.qml b/mix/qml/Block.qml new file mode 100644 index 000000000..e331dc6a6 --- /dev/null +++ b/mix/qml/Block.qml @@ -0,0 +1,145 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 +import QtQuick.Dialogs 1.1 +import QtQuick.Layouts 1.1 +import Qt.labs.settings 1.0 +import "js/Debugger.js" as Debugger +import "js/ErrorLocationFormater.js" as ErrorLocationFormater +import "." + +ColumnLayout +{ + property variant transactions + property string status + property int number + Rectangle + { + width: parent.width + height: 50 + anchors.left: parent.left + anchors.leftMargin: statusWidth + Label { + text: + { + if (status === "mined") + return qsTr("BLOCK") + " " + number + else + return qsTr("BLOCK") + " pending" + } + + anchors.left: parent.left + } + } + + Repeater // List of transactions + { + id: transactionRepeater + model: transactions + Row + { + height: 50 + Rectangle + { + id: trSaveStatus + color: "transparent" + CheckBox + { + id: saveStatus + checked: { + if (index >= 0) + return transactions.get(index).saveStatus + else + return true + } + onCheckedChanged: + { + if (index >= 0) + transactions.get(index).saveStatus = checked + } + } + } + + Rectangle + { + width: parent.width + height: 50 + color: "#cccccc" + radius: 4 + Row + { + Label + { + id: status + width: statusWidth + } + Label + { + id: hash + width: fromWidth + text: { + if (index >= 0) + return transactions.get(index).sender + else + return "" + } + + clip: true + } + Label + { + id: func + text: { + if (index >= 0) + parent.userFrienldyToken(transactions.get(index).label) + else + return "" + } + + width: toWidth + clip: true + } + + function userFrienldyToken(value) + { + if (value && value.indexOf("<") === 0) + return value.split(" - ")[0].replace("<", "") + "." + value.split("> ")[1] + "()"; + else + return value + } + + Label + { + id: returnValue + width: valueWidth + text: { + if (index >= 0 && transactions.get(index).returned) + return transactions.get(index).returned + else + return "" + } + clip: true + } + + Button + { + id: debug + width: logsWidth + text: "debug" + onClicked: + { + clientModel.debugRecord(transactions.get(index).recordIndex); + } + } + + Label + { + id: logs + width: logsWidth + } + } + } + } + } +} + diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml new file mode 100644 index 000000000..6e87ed52d --- /dev/null +++ b/mix/qml/BlockChain.qml @@ -0,0 +1,306 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 +import QtQuick.Dialogs 1.1 +import QtQuick.Layouts 1.1 +import Qt.labs.settings 1.0 +import org.ethereum.qml.QEther 1.0 +import "js/Debugger.js" as Debugger +import "js/ErrorLocationFormater.js" as ErrorLocationFormater +import "js/TransactionHelper.js" as TransactionHelper +import "js/QEtherHelper.js" as QEtherHelper +import "." + +Column { + id: blockChainPanel + property variant model + spacing: 5 + + function load(scenario) + { + + if (!scenario) + return; + model = scenario + blockModel.clear() + for (var b in model.blocks) + blockModel.append(model.blocks[b]) + } + + property int statusWidth: 50 + property int fromWidth: 100 + property int toWidth: 250 + property int valueWidth: 100 + property int logsWidth: 50 + + Row + { + id: header + width: parent.width + Label + { + text: "Status" + width: statusWidth + } + Label + { + text: "From" + width: fromWidth + } + Label + { + text: "To" + width: toWidth + } + Label + { + text: "Value" + width: valueWidth + } + Label + { + text: "Logs" + width: logsWidth + } + } + + Rectangle + { + width: parent.width + height: 500 + border.color: "#cccccc" + border.width: 2 + color: "white" + ScrollView + { + width: parent.width + height: parent.height + ColumnLayout + { + Repeater // List of blocks + { + id: blockChainRepeater + width: parent.width + model: blockModel + Block + { + height: + { + if (index >= 0) + return 50 + 50 * blockModel.get(index).transactions.length + else + return 0 + } + + transactions: + { + if (index >= 0) + return blockModel.get(index).transactions + else + return [] + } + + status: + { + if (index >= 0) + return blockModel.get(index).status + else + return "" + } + + number: + { + if (index >= 0) + return blockModel.get(index).number + else + return 0 + } + } + } + } + } + } + + ListModel + { + id: blockModel + + function appendBlock(block) + { + blockModel.append(block); + } + + function appendTransaction(tr) + { + blockModel.get(blockModel.count - 1).transactions.append(tr) + } + + function removeTransaction(blockIndex, trIndex) + { + console.log(blockIndex) + console.log(trIndex) + blockModel.get(blockIndex).transactions.remove(trIndex) + } + + function removeLastBlock() + { + blockModel.remove(blockModel.count - 1) + } + + function removeBlock(index) + { + blockModel.remove(index) + } + + function getTransaction(block, tr) + { + return blockModel.get(block - 1).transactions.get(tr) + } + } + + RowLayout + { + width: parent.width + Button { + id: rebuild + text: qsTr("Rebuild") + onClicked: + { + for (var j = 0; j < model.blocks.length; j++) + { + for (var k = 0; k < model.blocks[j].transactions.length; k++) + { + if (!blockModel.get(j).transactions.get(k).saveStatus) + { + model.blocks[j].transactions.splice(k, 1) + blockModel.removeTransaction(j, k) + if (model.blocks[j].transactions.length === 0) + { + model.blocks[j].splice(j, 1); + blockModel.removeBlock(j); + } + } + } + } + clientModel.setupScenario(model); + } + } + + Button { + id: addTransaction + text: qsTr("Add Transaction") + onClicked: + { + var lastBlock = model.blocks[model.blocks.length - 1]; + if (lastBlock.status === "mined") + model.blocks.push(projectModel.stateListModel.createEmptyBlock()); + var item = TransactionHelper.defaultTransaction() + transactionDialog.stateAccounts = model.accounts + transactionDialog.open(model.blocks[model.blocks.length - 1].transactions.length, model.blocks.length - 1, item) + } + } + + Button { + id: addBlockBtn + text: qsTr("Add Block") + onClicked: + { + var lastBlock = model.blocks[model.blocks.length - 1] + if (lastBlock.status === "pending") + clientModel.mine() + else + addNewBlock() + } + + function addNewBlock() + { + var block = projectModel.stateListModel.createEmptyBlock() + model.blocks.push(block) + blockModel.appendBlock(block) + } + } + + Connections + { + target: clientModel + onNewBlock: + { + if (!clientModel.running) + { + var lastBlock = model.blocks[model.blocks.length - 1] + lastBlock.status = "mined" + lastBlock.number = model.blocks.length + var lastB = blockModel.get(model.blocks.length - 1) + lastB.status = "mined" + lastB.number = model.blocks.length + addBlockBtn.addNewBlock() + } + } + onStateCleared: + { + } + onNewRecord: + { + var blockIndex = _r.transactionIndex.split(":")[0] + var trIndex = _r.transactionIndex.split(":")[1] + if (parseInt(blockIndex) <= model.blocks.length) + { + var item = model.blocks[parseInt(blockIndex) - 1]; + if (parseInt(trIndex) <= item.transactions.length) + { + var tr = item.transactions[parseInt(trIndex)]; + tr.returned = _r.returned; + blockModel.getTransaction(blockIndex, trIndex).returned = _r.returned; + tr.recordIndex = _r.recordIndex; + blockModel.getTransaction(blockIndex, trIndex).recordIndex = _r.recordIndex; + return; + } + } + + // tr is not in the list. coming from JavaScript + var itemTr = TransactionHelper.defaultTransaction() + itemTr.functionId = _r.function + itemTr.contractId = _r.contract + itemTr.gasAuto = true + itemTr.parameters = _r.parameters + itemTr.isContractCreation = itemTr.functionId === itemTr.contractId + itemTr.label = _r.label + itemTr.isFunctionCall = itemTr.functionId !== "" + itemTr.returned = _r.returned + itemTr.value = QEtherHelper.createEther(_r.value, QEther.Wei) + itemTr.sender = _r.sender + itemTr.recordIndex = _r.recordIndex + + model.blocks[model.blocks.length - 1].transactions.push(itemTr) + blockModel.appendTransaction(itemTr) + } + onMiningComplete: + { + } + } + + Button { + id: newAccount + text: qsTr("New Account") + onClicked: { + model.accounts.push(projectModel.stateListModel.newAccount("1000000", QEther.Ether)) + } + } + } + + TransactionDialog { + id: transactionDialog + onAccepted: { + var item = transactionDialog.getItem() + var lastBlock = model.blocks[model.blocks.length - 1]; + if (lastBlock.status === "mined") + model.blocks.push(projectModel.stateListModel.createEmptyBlock()); + model.blocks[model.blocks.length - 1].transactions.push(item) + blockModel.appendTransaction(item) + if (!clientModel.running) + clientModel.executeTr(item) + } + } +} + + diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index 9decc91ae..7827931b0 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -11,7 +11,6 @@ import "." Rectangle { id: debugPanel - property alias transactionLog: transactionLog property alias debugSlider: statesSlider property alias solLocals: solLocals property alias solStorage: solStorage @@ -23,7 +22,7 @@ Rectangle { signal debugExecuteLocation(string documentId, var location) property string compilationErrorMessage property bool assemblyMode: false - + signal panelClosed objectName: "debugPanel" color: "#ededed" clip: true @@ -61,7 +60,6 @@ Rectangle { { Debugger.init(data); debugScrollArea.visible = true; - compilationErrorArea.visible = false; machineStates.visible = true; } if (giveFocus) @@ -97,85 +95,21 @@ Rectangle { Settings { id: splitSettings - property alias transactionLogHeight: transactionLog.height property alias callStackHeight: callStackRect.height property alias storageHeightSettings: storageRect.height property alias memoryDumpHeightSettings: memoryRect.height property alias callDataHeightSettings: callDataRect.height - property alias transactionLogVisible: transactionLog.visible property alias solCallStackHeightSettings: solStackRect.height property alias solStorageHeightSettings: solStorageRect.height property alias solLocalsHeightSettings: solLocalsRect.height } - Rectangle - { - visible: false; - id: compilationErrorArea - width: parent.width - 20 - height: 600 - color: "#ededed" - anchors.left: parent.left - anchors.top: parent.top - anchors.margins: 10 - ColumnLayout - { - width: parent.width - anchors.top: parent.top - spacing: 15 - Rectangle - { - height: 15 - Button { - text: qsTr("Back to Debugger") - onClicked: { - debugScrollArea.visible = true; - compilationErrorArea.visible = false; - machineStates.visible = true; - } - } - } - - RowLayout - { - height: 100 - ColumnLayout - { - Text { - color: "red" - id: errorLocation - } - Text { - color: "#4a4a4a" - id: errorDetail - } - } - } - - Rectangle - { - width: parent.width - 6 - height: 2 - color: "#d0d0d0" - } - - RowLayout - { - Text - { - color: "#4a4a4a" - id: errorLine - } - } - } - } - - Splitter { + Splitter { id: debugScrollArea anchors.fill: parent orientation: Qt.Vertical - TransactionLog { + /*TransactionLog { id: transactionLog Layout.fillWidth: true Layout.minimumHeight: 130 @@ -186,7 +120,13 @@ Rectangle { anchors.leftMargin: machineStates.sideMargin anchors.rightMargin: machineStates.sideMargin anchors.topMargin: machineStates.sideMargin - } + }*/ + + Button + { + text: qsTr("close") + onClicked: panelClosed() + } ScrollView { @@ -230,7 +170,7 @@ Rectangle { spacing: 3 layoutDirection: Qt.LeftToRight - StepActionImage + /*StepActionImage { id: playAction enabledStateImg: "qrc:/qml/img/play_button.png" @@ -254,7 +194,7 @@ Rectangle { buttonShortcut: "Ctrl+Shift+F9" buttonTooltip: qsTr("Stop Debugging") visible: true - } + }*/ StepActionImage { diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index 67f45f973..4af8ece46 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -20,13 +20,14 @@ Rectangle { anchors.fill: parent id: root - property alias rightViewVisible: rightView.visible + property alias rightViewVisible: scenarioExe.visible property alias webViewVisible: webPreview.visible property alias webView: webPreview property alias projectViewVisible: projectList.visible property alias projectNavigator: projectList property alias runOnProjectLoad: mainSettings.runOnProjectLoad - property alias rightPane: rightView + property alias rightPane: scenarioExe + property alias debuggerPanel: debugPanel property alias codeEditor: codeEditor property bool webViewHorizontal: codeWebSplitter.orientation === Qt.Vertical //vertical splitter positions elements vertically, splits screen horizontally property bool firstCompile: true @@ -42,17 +43,17 @@ Rectangle { } } - Connections { - target: rightView - onDebugExecuteLocation: { + Connections { + target: debugPanel + onDebugExecuteLocation: { codeEditor.highlightExecution(documentId, location); } - } + } Connections { target: codeEditor onBreakpointsChanged: { - rightPane.setBreakpoints(codeEditor.getBreakpoints()); + debugPanel.setBreakpoints(codeEditor.getBreakpoints()); } } @@ -63,20 +64,20 @@ Rectangle { } function toggleRightView() { - rightView.visible = !rightView.visible; + scenarioExe.visible = !scenarioExe.visible; } function ensureRightView() { - rightView.visible = true; + scenarioExe.visible = true; } function rightViewIsVisible() { - return rightView.visible; + return scenarioExe.visible; } function hideRightView() { - rightView.visible = false; + scenarioExe.visible = lfalse; } function toggleWebPreview() { @@ -98,8 +99,8 @@ Rectangle { function displayCompilationErrorIfAny() { - rightView.visible = true; - rightView.displayCompilationErrorIfAny(); + scenarioExe.visible = true; + scenarioExe.displayCompilationErrorIfAny(); } Settings { @@ -153,7 +154,7 @@ Rectangle { id: splitSettings property alias projectWidth: projectList.width property alias contentViewWidth: contentView.width - property alias rightViewWidth: rightView.width + property alias rightViewWidth: scenarioExe.width } Splitter @@ -198,14 +199,41 @@ Rectangle { } } - Debugger { - visible: false; - id: rightView; - Layout.fillHeight: true - Keys.onEscapePressed: visible = false - Layout.minimumWidth: 515 - anchors.right: parent.right - } + ScenarioExecution + { + id: scenarioExe; + visible: false; + Layout.fillHeight: true + Keys.onEscapePressed: visible = false + Layout.minimumWidth: 650 + anchors.right: parent.right + } + + Debugger + { + id: debugPanel + visible: false + Layout.fillHeight: true + Keys.onEscapePressed: visible = false + Layout.minimumWidth: 650 + anchors.right: parent.right + } + + Connections { + target: clientModel + onDebugDataReady: { + scenarioExe.visible = false + debugPanel.visible = true + } + } + + Connections { + target: debugPanel + onPanelClosed: { + scenarioExe.visible = true + debugPanel.visible = false + } + } } } } diff --git a/mix/qml/QAddressView.qml b/mix/qml/QAddressView.qml index c880f0904..3c34d45eb 100644 --- a/mix/qml/QAddressView.qml +++ b/mix/qml/QAddressView.qml @@ -40,20 +40,28 @@ Item accountRef.clear(); accountRef.append({"itemid": " - "}); - if (subType === "contract" || subType === "address") + console.log(blockIndex) + console.log(transactionIndex) + if (subType === "contract" || subType === "address") { var trCr = 0; - for (var k = 0; k < transactionsModel.count; k++) - { - if (k >= transactionIndex) - break; - var tr = transactionsModel.get(k); - if (tr.functionId === tr.contractId /*&& (dec[1] === tr.contractId || item.subType === "address")*/) - { - accountRef.append({ "itemid": tr.contractId + " - " + trCr, "value": "<" + tr.contractId + " - " + trCr + ">", "type": "contract" }); - trCr++; - } - } + if (blockChainPanel) + for (var k = 0; k < blockChainPanel.model.blocks.length; k++) + { + if (k > blockIndex) + break; + for (var i = 0; i < blockChainPanel.model.blocks[k].transactions.length; i++) + { + if (i > transactionIndex) + break; + var tr = blockChainPanel.model.blocks[k].transactions[i] + if (tr.functionId === tr.contractId /*&& (dec[1] === tr.contractId || item.subType === "address")*/) + { + accountRef.append({ "itemid": tr.contractId + " - " + trCr, "value": "<" + tr.contractId + " - " + trCr + ">", "type": "contract" }); + trCr++; + } + } + } } if (subType === "address") { diff --git a/mix/qml/ScenarioExecution.qml b/mix/qml/ScenarioExecution.qml new file mode 100644 index 000000000..5fcbfab3e --- /dev/null +++ b/mix/qml/ScenarioExecution.qml @@ -0,0 +1,57 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 +import QtQuick.Dialogs 1.1 +import QtQuick.Layouts 1.1 +import Qt.labs.settings 1.0 +import "js/Debugger.js" as Debugger +import "js/ErrorLocationFormater.js" as ErrorLocationFormater +import "." + +Rectangle { + + border.color: "red" + border.width: 1 + + Connections + { + target: projectModel + onProjectLoaded: { + loader.init() + } + + } + + Column + { + anchors.margins: 10 + anchors.fill: parent + spacing: 5 + ScenarioLoader + { + width: parent.width + id: loader + } + + Rectangle + { + width: parent.width + height: 1 + color: "#cccccc" + } + + Connections + { + target: loader + onLoaded: { + blockChain.load(scenario) + } + } + + BlockChain + { + id: blockChain + width: parent.width + } + } +} diff --git a/mix/qml/ScenarioLoader.qml b/mix/qml/ScenarioLoader.qml new file mode 100644 index 000000000..0b703c860 --- /dev/null +++ b/mix/qml/ScenarioLoader.qml @@ -0,0 +1,77 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 1.1 +import QtQuick.Dialogs 1.1 +import QtQuick.Layouts 1.1 +import Qt.labs.settings 1.0 +import "js/Debugger.js" as Debugger +import "js/ErrorLocationFormater.js" as ErrorLocationFormater +import "." + +RowLayout +{ + signal restored(variant scenario) + signal saved(variant scenario) + signal duplicated(variant scenario) + signal loaded(variant scenario) + + function init() + { + scenarioList.load() + } + + id: blockChainSelector + ComboBox + { + id: scenarioList + model: projectModel.stateListModel + textRole: "title" + onCurrentIndexChanged: + { + restoreScenario.restore() + } + + function load() + { + var state = projectModel.stateListModel.getState(currentIndex) + loaded(state) + } + } + Button + { + id: restoreScenario + text: qsTr("Restore") + onClicked: { + restore() + } + + function restore() + { + var state = projectModel.stateListModel.reloadStateFromFromProject(scenarioList.currentIndex) + restored(state) + loaded(state) + } + + } + Button + { + id: saveScenario + text: qsTr("Save") + onClicked: { + projectModel.saveProjectFile() + saved(state) + } + } + Button + { + id: duplicateScenario + text: qsTr("Duplicate") + onClicked: { + var state = JSON.parse(JSON.stringify(projectModel.stateListModel.getState(scenarioList.currentIndex))) + state.title = qsTr("Copy of ") + state.title; + projectModel.stateListModel.appendState(state) + projectModel.stateListModel.save() + duplicated(state) + } + } +} diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index d3062af9e..d08ed668d 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -23,7 +23,8 @@ Item { return { title: s.title, transactions: s.transactions.filter(function(t) { return !t.stdContract; }).map(fromPlainTransactionItem), //support old projects by filtering std contracts - accounts: s.accounts.map(fromPlainAccountItem), + blocks: s.blocks.map(fromPlainBlockItem), + accounts: s.accounts.map(fromPlainAccountItem), contracts: s.contracts.map(fromPlainAccountItem), miner: s.miner }; @@ -58,7 +59,8 @@ Item { sender: t.sender, isContractCreation: t.isContractCreation, label: t.label, - isFunctionCall: t.isFunctionCall + isFunctionCall: t.isFunctionCall, + saveStatus: t.saveStatus }; if (r.isFunctionCall === undefined) @@ -76,10 +78,22 @@ Item { return r; } + function fromPlainBlockItem(b) + { + var r = { + hash: b.hash, + number: b.number, + transactions: b.transactions.filter(function(t) { return !t.stdContract; }).map(fromPlainTransactionItem), //support old projects by filtering std contracts + status: b.status + } + return r; + } + function toPlainStateItem(s) { return { title: s.title, - transactions: s.transactions.map(toPlainTransactionItem), + blocks: s.blocks.map(toPlainBlockItem), + transactions: s.transactions.map(toPlainTransactionItem), accounts: s.accounts.map(toPlainAccountItem), contracts: s.contracts.map(toPlainAccountItem), miner: s.miner @@ -96,6 +110,17 @@ Item { return ''; } + function toPlainBlockItem(b) + { + var r = { + hash: b.hash, + number: b.number, + transactions: b.transactions.map(toPlainTransactionItem), + status: b.status + } + return r; + } + function toPlainAccountItem(t) { return { @@ -112,6 +137,7 @@ Item { } function toPlainTransactionItem(t) { + console.log(JSON.stringify(t)); var r = { type: t.type, contractId: t.contractId, @@ -125,7 +151,8 @@ Item { parameters: {}, isContractCreation: t.isContractCreation, label: t.label, - isFunctionCall: t.isFunctionCall + isFunctionCall: t.isFunctionCall, + saveStatus: t.saveStatus }; for (var key in t.parameters) r.parameters[key] = t.parameters[key]; @@ -146,14 +173,16 @@ Item { projectData.states.push(toPlainStateItem(stateList[i])); } projectData.defaultStateIndex = stateListModel.defaultStateIndex; - } + stateListModel.data = projectData + + } onNewProject: { var state = toPlainStateItem(stateListModel.createDefaultState()); state.title = qsTr("Default"); projectData.states = [ state ]; projectData.defaultStateIndex = 0; - stateListModel.loadStatesFromProject(projectData); - } + stateListModel.loadStatesFromProject(projectData); + } } Connections { @@ -170,34 +199,40 @@ Item { id: stateDialog onAccepted: { var item = stateDialog.getItem(); - if (stateDialog.stateIndex < stateListModel.count) { - if (stateDialog.isDefault) - stateListModel.defaultStateIndex = stateIndex; - stateList[stateDialog.stateIndex] = item; - stateListModel.set(stateDialog.stateIndex, item); - } else { - if (stateDialog.isDefault) - stateListModel.defaultStateIndex = 0; - stateList.push(item); - stateListModel.append(item); - } - if (stateDialog.isDefault) - stateListModel.defaultStateChanged(); - stateListModel.save(); + saveState(item); } + + function saveState(item) + { + if (stateDialog.stateIndex < stateListModel.count) { + if (stateDialog.isDefault) + stateListModel.defaultStateIndex = stateIndex; + stateList[stateDialog.stateIndex] = item; + stateListModel.set(stateDialog.stateIndex, item); + } else { + if (stateDialog.isDefault) + stateListModel.defaultStateIndex = 0; + stateList.push(item); + stateListModel.append(item); + } + if (stateDialog.isDefault) + stateListModel.defaultStateChanged(); + stateListModel.save(); + } } ListModel { id: stateListModel property int defaultStateIndex: 0 - signal defaultStateChanged; + property variant data + signal defaultStateChanged; signal stateListModelReady; signal stateRun(int index) signal stateDeleted(int index) function defaultTransactionItem() { return TransactionHelper.defaultTransaction(); - } + } function newAccount(_balance, _unit, _secret) { @@ -208,15 +243,26 @@ Item { return { name: name, secret: _secret, balance: QEtherHelper.createEther(_balance, _unit), address: address }; } + function createEmptyBlock() + { + return { + hash: "", + number: -1, + transactions: [], + status: "pending" + } + } + function createDefaultState() { var item = { title: "", transactions: [], accounts: [], - contracts: [] - }; + contracts: [], + blocks: [{ status: "pending", number: -1, hash: "", transactions: []}] + }; - var account = newAccount("1000000", QEther.Ether, defaultAccount) + var account = newAccount("1000000", QEther.Ether, defaultAccount) item.accounts.push(account); item.miner = account; @@ -228,7 +274,8 @@ Item { ctorTr.label = qsTr("Deploy") + " " + ctorTr.contractId; ctorTr.sender = item.accounts[0].secret; item.transactions.push(ctorTr); - } + item.blocks[0].transactions.push(ctorTr) + } return item; } @@ -284,10 +331,20 @@ Item { stateDialog.open(stateListModel.count, item, false); } + function appendState(item) + { + stateListModel.append(item); + stateList.push(item); + } + function editState(index) { stateDialog.open(index, stateList[index], defaultStateIndex === index); } + function getState(index) { + return stateList[index]; + } + function debugDefaultState() { if (defaultStateIndex >= 0 && defaultStateIndex < stateList.length) runState(defaultStateIndex); @@ -295,8 +352,8 @@ Item { function runState(index) { var item = stateList[index]; - clientModel.setupState(item); - stateRun(index); + //clientModel.setupState(item); + //stateRun(index); } function deleteState(index) { @@ -322,8 +379,22 @@ Item { return stateList[defaultStateIndex].title; } + function reloadStateFromFromProject(index) + { + console.log(JSON.stringify(data)) + if (data) + { + var item = fromPlainStateItem(data.states[index]) + + stateListModel.set(index, item) + stateList[index] = item + return item + } + } + function loadStatesFromProject(projectData) { + data = projectData if (!projectData.states) projectData.states = []; if (projectData.defaultStateIndex !== undefined) diff --git a/mix/qml/StructView.qml b/mix/qml/StructView.qml index 029fd162d..9cb461204 100644 --- a/mix/qml/StructView.qml +++ b/mix/qml/StructView.qml @@ -9,6 +9,7 @@ Column property alias members: repeater.model //js array property variant accounts property var value: ({}) + property int blockIndex property int transactionIndex property string context Layout.fillWidth: true diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index df5ad781b..b53c7c787 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -17,6 +17,7 @@ Dialog { visible: false title: qsTr("Edit Transaction") property int transactionIndex + property int blockIndex property alias gas: gasValueEdit.gasValue; property alias gasAuto: gasAutoCheck.checked; property alias gasPrice: gasPriceField.value; @@ -27,21 +28,24 @@ Dialog { property var paramsModel: []; property bool useTransactionDefaultValue: false property alias stateAccounts: senderComboBox.model + property bool saveStatus signal accepted; StateDialogStyle { id: transactionDialogStyle } - function open(index, item) { + function open(index, blockIdx, item) { rowFunction.visible = !useTransactionDefaultValue; rowValue.visible = !useTransactionDefaultValue; rowGas.visible = !useTransactionDefaultValue; rowGasPrice.visible = !useTransactionDefaultValue; - transactionIndex = index; - typeLoader.transactionIndex = index; - + transactionIndex = index + blockIndex = blockIdx + typeLoader.transactionIndex = index + typeLoader.blockIndex = blockIdx + saveStatus = item.saveStatus gasValueEdit.gasValue = item.gas; gasAutoCheck.checked = item.gasAuto ? true : false; gasPriceField.value = item.gasPrice; @@ -229,7 +233,7 @@ Dialog { item.functionId = item.contractId; item.label = qsTr("Deploy") + " " + item.contractId; } - + item.saveStatus = saveStatus item.sender = senderComboBox.model[senderComboBox.currentIndex].secret; item.parameters = paramValues; return item; diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 6fce7686d..1e6169e5d 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -101,6 +101,8 @@ function loadProject(path) { console.log("Loading project at " + path); var projectFile = path + projectFileName; var json = fileIo.readFile(projectFile); + if (!json) + return; var projectData = JSON.parse(json); if (projectData.deploymentDir) projectModel.deploymentDir = projectData.deploymentDir diff --git a/mix/qml/js/TransactionHelper.js b/mix/qml/js/TransactionHelper.js index b9a011b66..8a7c5f5b8 100644 --- a/mix/qml/js/TransactionHelper.js +++ b/mix/qml/js/TransactionHelper.js @@ -12,7 +12,8 @@ function defaultTransaction() stdContract: false, isContractCreation: true, label: "", - isFunctionCall: true + isFunctionCall: true, + saveStatus: true }; } From 799ff95c28e4092694aadd1aeb07d1d4e3d915ba Mon Sep 17 00:00:00 2001 From: yann300 Date: Sun, 7 Jun 2015 12:19:04 +0200 Subject: [PATCH 02/40] - Catch events for each incoming transaction. --- mix/ClientModel.cpp | 302 ++++++++++-------- mix/ClientModel.h | 7 +- mix/ContractCallDataEncoder.cpp | 12 +- mix/ContractCallDataEncoder.h | 4 +- mix/MachineStates.h | 1 + mix/MixClient.cpp | 547 ++++++++++++++++---------------- mix/MixClient.h | 2 +- mix/QContractDefinition.cpp | 17 +- mix/QContractDefinition.h | 8 + mix/QFunctionDefinition.cpp | 32 +- mix/QFunctionDefinition.h | 7 + mix/QVariableDeclaration.cpp | 13 +- mix/QVariableDeclaration.h | 9 +- mix/qml/Block.qml | 28 +- mix/qml/BlockChain.qml | 11 +- 15 files changed, 571 insertions(+), 429 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 3cd401e23..156a5285f 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "DebuggingStateWrapper.h" #include "Exceptions.h" #include "QContractDefinition.h" @@ -82,7 +83,7 @@ ClientModel::ClientModel(): qRegisterMetaType("QCallData"); qRegisterMetaType("RecordLogEntry*"); - //connect(this, &ClientModel::runComplete, this, &ClientModel::showDebugger, Qt::QueuedConnection); + //connect(this, &ClientModel::runComplete, this, &ClientModel::showDebugger, Qt::QueuedConnection); m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString())); m_ethAccounts = make_shared([=](){return m_client.get();}, std::vector()); @@ -113,7 +114,7 @@ QString ClientModel::apiCall(QString const& _message) void ClientModel::mine() { - if (m_mining) + if (m_mining) BOOST_THROW_EXCEPTION(ExecutionStateException()); m_mining = true; emit miningStarted(); @@ -210,108 +211,108 @@ QVariantList ClientModel::gasCosts() const void ClientModel::setupScenario(QVariantMap _scenario) { - m_queueTransactions.clear(); - m_running = true; - - m_currentScenario = _scenario; - QVariantList blocks = _scenario.value("blocks").toList(); - QVariantList stateAccounts = _scenario.value("accounts").toList(); - - m_accounts.clear(); - std::vector userAccounts; - - for (auto const& b: stateAccounts) - { - QVariantMap account = b.toMap(); - Address address = {}; - if (account.contains("secret")) - { - KeyPair key(Secret(account.value("secret").toString().toStdString())); - userAccounts.push_back(key); - address = key.address(); - } - else if (account.contains("address")) - address = Address(fromHex(account.value("address").toString().toStdString())); - if (!address) - continue; - - m_accounts[address] = Account(qvariant_cast(account.value("balance"))->toU256Wei(), Account::NormalCreation); - } - m_ethAccounts->setAccounts(userAccounts); - for (auto const& b: blocks) - { - QVariantList transactions = b.toMap().value("transactions").toList(); - m_queueTransactions.push_back(transactions); - } - - m_client->resetState(m_accounts, Secret(m_currentScenario.value("miner").toMap().value("secret").toString().toStdString())); - - connect(this, &ClientModel::newBlock, this, &ClientModel::processNextBlock, Qt::QueuedConnection); - connect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution, Qt::QueuedConnection); - connect(this, &ClientModel::runStateChanged, this, &ClientModel::finalizeBlock, Qt::QueuedConnection); - processNextBlock(); + m_queueTransactions.clear(); + m_running = true; + + m_currentScenario = _scenario; + QVariantList blocks = _scenario.value("blocks").toList(); + QVariantList stateAccounts = _scenario.value("accounts").toList(); + + m_accounts.clear(); + std::vector userAccounts; + + for (auto const& b: stateAccounts) + { + QVariantMap account = b.toMap(); + Address address = {}; + if (account.contains("secret")) + { + KeyPair key(Secret(account.value("secret").toString().toStdString())); + userAccounts.push_back(key); + address = key.address(); + } + else if (account.contains("address")) + address = Address(fromHex(account.value("address").toString().toStdString())); + if (!address) + continue; + + m_accounts[address] = Account(qvariant_cast(account.value("balance"))->toU256Wei(), Account::NormalCreation); + } + m_ethAccounts->setAccounts(userAccounts); + for (auto const& b: blocks) + { + QVariantList transactions = b.toMap().value("transactions").toList(); + m_queueTransactions.push_back(transactions); + } + + m_client->resetState(m_accounts, Secret(m_currentScenario.value("miner").toMap().value("secret").toString().toStdString())); + + connect(this, &ClientModel::newBlock, this, &ClientModel::processNextBlock, Qt::QueuedConnection); + connect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution, Qt::QueuedConnection); + connect(this, &ClientModel::runStateChanged, this, &ClientModel::finalizeBlock, Qt::QueuedConnection); + processNextBlock(); } void ClientModel::stopExecution() { - disconnect(this, &ClientModel::newBlock, this, &ClientModel::processNextBlock); - disconnect(this, &ClientModel::runStateChanged, this, &ClientModel::finalizeBlock); - disconnect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution); - m_running = false; + disconnect(this, &ClientModel::newBlock, this, &ClientModel::processNextBlock); + disconnect(this, &ClientModel::runStateChanged, this, &ClientModel::finalizeBlock); + disconnect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution); + m_running = false; } void ClientModel::finalizeBlock() { - if (m_queueTransactions.size() > 0) - mine(); - else - { - disconnect(this, &ClientModel::newBlock, this, &ClientModel::processNextBlock); - disconnect(this, &ClientModel::runStateChanged, this, &ClientModel::finalizeBlock); - disconnect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution); - m_running = false; - emit runComplete(); - } + if (m_queueTransactions.size() > 0) + mine(); + else + { + disconnect(this, &ClientModel::newBlock, this, &ClientModel::processNextBlock); + disconnect(this, &ClientModel::runStateChanged, this, &ClientModel::finalizeBlock); + disconnect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution); + m_running = false; + emit runComplete(); + } } void ClientModel::processNextBlock() { - processNextTransactions(); + processNextTransactions(); } void ClientModel::processNextTransactions() { - vector transactionSequence; - for (auto const& t: m_queueTransactions.front()) - { - QVariantMap transaction = t.toMap(); - QString contractId = transaction.value("contractId").toString(); - QString functionId = transaction.value("functionId").toString(); - bool gasAuto = transaction.value("gasAuto").toBool(); - u256 gas = 0; - if (transaction.value("gas").data()) - gas = boost::get(qvariant_cast(transaction.value("gas"))->internalValue()); - else - gasAuto = true; - - u256 value = (qvariant_cast(transaction.value("value")))->toU256Wei(); - u256 gasPrice = (qvariant_cast(transaction.value("gasPrice")))->toU256Wei(); - QString sender = transaction.value("sender").toString(); - bool isContractCreation = transaction.value("isContractCreation").toBool(); - bool isFunctionCall = transaction.value("isFunctionCall").toBool(); - if (contractId.isEmpty() && m_codeModel->hasContract()) //TODO: This is to support old project files, remove later - contractId = m_codeModel->contracts().keys()[0]; - TransactionSettings transactionSettings(contractId, functionId, value, gas, gasAuto, gasPrice, Secret(sender.toStdString()), isContractCreation, isFunctionCall); - transactionSettings.parameterValues = transaction.value("parameters").toMap(); - - if (contractId == functionId || functionId == "Constructor") - transactionSettings.functionId.clear(); - - transactionSequence.push_back(transactionSettings); - } - m_queueTransactions.pop_front(); - executeSequence(transactionSequence); + vector transactionSequence; + for (auto const& t: m_queueTransactions.front()) + { + QVariantMap transaction = t.toMap(); + QString contractId = transaction.value("contractId").toString(); + QString functionId = transaction.value("functionId").toString(); + bool gasAuto = transaction.value("gasAuto").toBool(); + u256 gas = 0; + if (transaction.value("gas").data()) + gas = boost::get(qvariant_cast(transaction.value("gas"))->internalValue()); + else + gasAuto = true; + + u256 value = (qvariant_cast(transaction.value("value")))->toU256Wei(); + u256 gasPrice = (qvariant_cast(transaction.value("gasPrice")))->toU256Wei(); + QString sender = transaction.value("sender").toString(); + bool isContractCreation = transaction.value("isContractCreation").toBool(); + bool isFunctionCall = transaction.value("isFunctionCall").toBool(); + if (contractId.isEmpty() && m_codeModel->hasContract()) //TODO: This is to support old project files, remove later + contractId = m_codeModel->contracts().keys()[0]; + TransactionSettings transactionSettings(contractId, functionId, value, gas, gasAuto, gasPrice, Secret(sender.toStdString()), isContractCreation, isFunctionCall); + transactionSettings.parameterValues = transaction.value("parameters").toMap(); + + if (contractId == functionId || functionId == "Constructor") + transactionSettings.functionId.clear(); + + transactionSequence.push_back(transactionSettings); + } + m_queueTransactions.pop_front(); + executeSequence(transactionSequence); } void ClientModel::executeSequence(vector const& _sequence) @@ -323,7 +324,7 @@ void ClientModel::executeSequence(vector const& _sequence) } emit runStarted(); - //emit runStateChanged(); + //emit runStateChanged(); //run sequence @@ -332,7 +333,7 @@ void ClientModel::executeSequence(vector const& _sequence) try { vector
deployedContracts; - //onStateReset(); + //onStateReset(); m_gasCosts.clear(); for (TransactionSettings const& transaction: _sequence) { @@ -360,7 +361,7 @@ void ClientModel::executeSequence(vector const& _sequence) break; } if (!f) - emit runFailed("Function '" + transaction.functionId + tr("' not found. Please check transactions or the contract code.")); + emit runFailed("Function '" + transaction.functionId + tr("' not found. Please check transactions or the contract code.")); if (!transaction.functionId.isEmpty()) encoder.encode(f); for (QVariableDeclaration const* p: f->parametersList()) @@ -391,62 +392,62 @@ void ClientModel::executeSequence(vector const& _sequence) { auto contractAddressIter = m_contractAddresses.find(ctrInstance); if (contractAddressIter == m_contractAddresses.end()) - emit runFailed("Contract '" + transaction.contractId + tr(" not deployed.") + "' " + tr(" Cannot call ") + transaction.functionId); - callAddress(contractAddressIter->second, encoder.encodedData(), transaction); + emit runFailed("Contract '" + transaction.contractId + tr(" not deployed.") + "' " + tr(" Cannot call ") + transaction.functionId); + callAddress(contractAddressIter->second, encoder.encodedData(), transaction); } m_gasCosts.append(m_client->lastExecution().gasUsed); onNewTransaction(); - emit runComplete(); - } + emit runComplete(); + } } catch(boost::exception const&) { cerr << boost::current_exception_diagnostic_information(); emit runFailed(QString::fromStdString(boost::current_exception_diagnostic_information())); - } + } catch(exception const& e) { cerr << boost::current_exception_diagnostic_information(); emit runFailed(e.what()); - } + } emit runStateChanged(); - }); + }); } void ClientModel::executeTr(QVariantMap _tr) { - QVariantList trs; - trs.push_back(_tr); - m_queueTransactions.push_back(trs); - processNextTransactions(); + QVariantList trs; + trs.push_back(_tr); + m_queueTransactions.push_back(trs); + processNextTransactions(); } std::pair ClientModel::resolvePair(QString const& _contractId) { - std::pair ret = std::make_pair(_contractId, 0); - if (_contractId.startsWith("<") && _contractId.endsWith(">")) - { - QStringList values = ret.first.remove("<").remove(">").split(" - "); - ret = std::make_pair(values[0], values[1].toUInt()); - } - return ret; + std::pair ret = std::make_pair(_contractId, 0); + if (_contractId.startsWith("<") && _contractId.endsWith(">")) + { + QStringList values = ret.first.remove("<").remove(">").split(" - "); + ret = std::make_pair(values[0], values[1].toUInt()); + } + return ret; } QString ClientModel::resolveToken(std::pair const& _value, vector
const& _contracts) { if (_contracts.size() > 0) - return QString::fromStdString("0x" + dev::toHex(m_contractAddresses[_value].ref())); //dev::toHex(_contracts.at(_value.second).ref())); + return QString::fromStdString("0x" + dev::toHex(m_contractAddresses[_value].ref())); //dev::toHex(_contracts.at(_value.second).ref())); else return _value.first; } std::pair ClientModel::retrieveToken(QString const& _value, vector
const& _contracts) { - std::pair ret; - ret.first = _value; - ret.second = _contracts.size() - 1; - return ret; + std::pair ret; + ret.first = _value; + ret.second = _contracts.size() - 1; + return ret; } void ClientModel::showDebugger() @@ -647,7 +648,7 @@ void ClientModel::emptyRecord() void ClientModel::debugRecord(unsigned _index) { ExecutionResult e = m_client->execution(_index); - showDebuggerForTransaction(e); + showDebuggerForTransaction(e); } Address ClientModel::deployContract(bytes const& _code, TransactionSettings const& _ctrTransaction) @@ -668,7 +669,7 @@ RecordLogEntry* ClientModel::lastBlock() const strGas << blockInfo.gasUsed; stringstream strNumber; strNumber << blockInfo.number; - RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(dev::toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str()), QString(), tr("Block"), QVariantMap()); + RecordLogEntry* record = new RecordLogEntry(0, QString::fromStdString(strNumber.str()), tr(" - Block - "), tr("Hash: ") + QString(QString::fromStdString(dev::toHex(blockInfo.hash().ref()))), QString(), QString(), QString(), false, RecordLogEntry::RecordType::Block, QString::fromStdString(strGas.str()), QString(), tr("Block"), QVariantMap(), QVariantList()); QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership); return record; } @@ -685,7 +686,7 @@ void ClientModel::onStateReset() void ClientModel::onNewTransaction() { ExecutionResult const& tr = m_client->lastExecution(); - unsigned block = m_client->number() + 1; + unsigned block = m_client->number() + 1; unsigned recordIndex = tr.executonIndex; QString transactionIndex = tr.isCall() ? QObject::tr("Call") : QString("%1:%2").arg(block).arg(tr.transactionIndex); QString address = QString::fromStdString(toJS(tr.address)); @@ -727,9 +728,11 @@ void ClientModel::onNewTransaction() Address contractAddress = (bool)tr.address ? tr.address : tr.contractAddress; auto contractAddressIter = m_contractNames.find(contractAddress); - QVariantMap inputParameters; + QVariantMap inputParameters; + QVariantList logs; if (contractAddressIter != m_contractNames.end()) { + ContractCallDataEncoder encoder; CompiledContract const& compilerRes = m_codeModel->contract(contractAddressIter->second); const QContractDefinition* def = compilerRes.contract(); contract = def->name(); @@ -739,25 +742,64 @@ void ClientModel::onNewTransaction() if (funcDef) { function = funcDef->name(); - ContractCallDataEncoder encoder; QStringList returnValues = encoder.decode(funcDef->returnParameters(), tr.result.output); returned += "("; returned += returnValues.join(", "); returned += ")"; - bytes data = tr.inputParameters; - data.erase(data.begin(), data.begin() + 4); - QStringList parameters = encoder.decode(funcDef->parametersList(), data); - for (int k = 0; k < parameters.length(); ++k) - inputParameters.insert(funcDef->parametersList().at(k)->name(), parameters.at(k)); - } + bytes data = tr.inputParameters; + data.erase(data.begin(), data.begin() + 4); + QStringList parameters = encoder.decode(funcDef->parametersList(), data); + for (int k = 0; k < parameters.length(); ++k) + inputParameters.insert(funcDef->parametersList().at(k)->name(), parameters.at(k)); + } } - } - LocalisedLogEntries logs = m_client->logs(); - QString sender = QString::fromStdString(dev::toHex(tr.sender.ref())); - QString label = contract + "." + function + "()"; - RecordLogEntry* log = new RecordLogEntry(recordIndex, transactionIndex, contract, function, value, address, returned, tr.isCall(), RecordLogEntry::RecordType::Transaction, - gasUsed, sender, label, inputParameters); + // Fill generated logs and decode parameters + for (auto const& log: tr.logs) + { + QVariantMap l; + l.insert("address", QString::fromStdString(log.address.hex())); + auto const& sign = log.topics.front(); // first hash supposed to be the event signature. To check + auto dataIterator = log.data.begin(); + int topicDataIndex = 1; + for (auto const& event: def->eventsList()) + { + if (sign == event->fullHash()) + { + QVariantList paramsList; + l.insert("name", event->name()); + for (auto const& e: event->parametersList()) + { + bytes data; + QString param; + if (!e->isIndexed()) + { + data = bytes(dataIterator, dataIterator + 32); + dataIterator = dataIterator + 32; + } + else + { + data = log.topics.at(topicDataIndex).asBytes(); + topicDataIndex++; + } + param = encoder.decode(e, data); + QVariantMap p; + p.insert("indexed", e->isIndexed()); + p.insert("value", param); + p.insert("name", e->name()); + paramsList.push_back(p); + } + l.insert("param", paramsList); + break; + } + } + logs.push_back(l); + } + } + QString sender = QString::fromStdString(dev::toHex(tr.sender.ref())); + QString label = contract + "." + function + "()"; + RecordLogEntry* log = new RecordLogEntry(recordIndex, transactionIndex, contract, function, value, address, returned, tr.isCall(), RecordLogEntry::RecordType::Transaction, + gasUsed, sender, label, inputParameters, logs); QQmlEngine::setObjectOwnership(log, QQmlEngine::JavaScriptOwnership); emit newRecord(log); } diff --git a/mix/ClientModel.h b/mix/ClientModel.h index 503b4189f..7cc7b03f6 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -115,6 +115,8 @@ class RecordLogEntry: public QObject Q_PROPERTY(QString label MEMBER m_label CONSTANT) /// input parameters Q_PROPERTY(QVariantMap parameters MEMBER m_inputParameters CONSTANT) + /// logs + Q_PROPERTY(QVariantList logs MEMBER m_logs CONSTANT) public: enum RecordType @@ -126,9 +128,9 @@ public: RecordLogEntry(): m_recordIndex(0), m_call(false), m_type(RecordType::Transaction) {} RecordLogEntry(unsigned _recordIndex, QString _transactionIndex, QString _contract, QString _function, QString _value, QString _address, QString _returned, bool _call, RecordType _type, QString _gasUsed, - QString _sender, QString _label, QVariantMap _inputParameters): + QString _sender, QString _label, QVariantMap _inputParameters, QVariantList _logs): m_recordIndex(_recordIndex), m_transactionIndex(_transactionIndex), m_contract(_contract), m_function(_function), m_value(_value), m_address(_address), m_returned(_returned), m_call(_call), m_type(_type), m_gasUsed(_gasUsed), - m_sender(_sender), m_label(_label), m_inputParameters(_inputParameters) {} + m_sender(_sender), m_label(_label), m_inputParameters(_inputParameters), m_logs(_logs) {} private: unsigned m_recordIndex; @@ -144,6 +146,7 @@ private: QString m_sender; QString m_label; QVariantMap m_inputParameters; + QVariantList m_logs; }; /** diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 70c1e6068..553c5e075 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -228,16 +228,10 @@ QVariant ContractCallDataEncoder::decode(SolidityType const& _type, bytes const& BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Parameter declaration not found")); } -QStringList ContractCallDataEncoder::decode(QList const& _returnParameters, vector _value) +QString ContractCallDataEncoder::decode(QVariableDeclaration* const& _param, bytes _value) { - QStringList r; - for (int k = 0; k <_returnParameters.length(); k++) - { - QVariableDeclaration* dec = static_cast(_returnParameters.at(k)); - SolidityType const& type = dec->type()->type(); - r.append(decode(type, _value.at(k)).toString()); - } - return r; + SolidityType const& type = _param->type()->type(); + return decode(type, _value).toString(); } QStringList ContractCallDataEncoder::decode(QList const& _returnParameters, bytes _value) diff --git a/mix/ContractCallDataEncoder.h b/mix/ContractCallDataEncoder.h index 57b364b49..748239c5b 100644 --- a/mix/ContractCallDataEncoder.h +++ b/mix/ContractCallDataEncoder.h @@ -48,8 +48,8 @@ public: void encode(QVariant const& _data, SolidityType const& _type); /// Decode variable in order to be sent to QML view. QStringList decode(QList const& _dec, bytes _value); - /// Decode @param _parameters - QStringList decode(QList const& _parameters, std::vector _value); + /// Decode @param _parameter + QString decode(QVariableDeclaration* const& _param, bytes _value); /// Decode single variable QVariant decode(SolidityType const& _type, bytes const& _value); /// Get all encoded data encoded by encode function. diff --git a/mix/MachineStates.h b/mix/MachineStates.h index ae9804f7f..1b50c062b 100644 --- a/mix/MachineStates.h +++ b/mix/MachineStates.h @@ -84,6 +84,7 @@ namespace mix unsigned transactionIndex; unsigned executonIndex = 0; bytes inputParameters; + eth::LocalisedLogEntries logs; bool isCall() const { return transactionIndex == std::numeric_limits::max(); } bool isConstructor() const { return !isCall() && !address; } diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index fcc72db9d..fc2a153c5 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -1,18 +1,18 @@ /* - This file is part of cpp-ethereum. + This file is part of cpp-ethereum. - cpp-ethereum 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. + cpp-ethereum 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. - cpp-ethereum 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. + cpp-ethereum 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 cpp-ethereum. If not, see . + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . */ /** @file MixClient.cpp * @author Arkadiy Paronyan arkadiy@ethdev.com @@ -48,27 +48,27 @@ namespace struct MixPow //dummy POW { - typedef int Solution; - static void assignResult(int, BlockInfo const&) {} - static bool verify(BlockInfo const&) { return true; } + typedef int Solution; + static void assignResult(int, BlockInfo const&) {} + static bool verify(BlockInfo const&) { return true; } }; } bytes MixBlockChain::createGenesisBlock(h256 _stateRoot) { - RLPStream block(3); - block.appendList(15) - << h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie - << LogBloom() << c_mixGenesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 - << std::string() << h256() << h64(u64(42)); - block.appendRaw(RLPEmptyList); - block.appendRaw(RLPEmptyList); - return block.out(); + RLPStream block(3); + block.appendList(15) + << h256() << EmptyListSHA3 << h160() << _stateRoot << EmptyTrie << EmptyTrie + << LogBloom() << c_mixGenesisDifficulty << 0 << c_genesisGasLimit << 0 << (unsigned)0 + << std::string() << h256() << h64(u64(42)); + block.appendRaw(RLPEmptyList); + block.appendRaw(RLPEmptyList); + return block.out(); } MixClient::MixClient(std::string const& _dbPath): - m_dbPath(_dbPath) + m_dbPath(_dbPath) { resetState(std::unordered_map()); } @@ -85,335 +85,350 @@ LocalisedLogEntries MixClient::logs() void MixClient::resetState(std::unordered_map const& _accounts, Secret const& _miner) { - WriteGuard l(x_state); - Guard fl(x_filtersWatches); - m_filters.clear(); - m_watches.clear(); - LogFilter filter; - m_filters.insert(std::make_pair(filter.sha3(), filter)); - m_watches.insert(std::make_pair(0, ClientWatch(filter.sha3(), Reaping::Automatic))); - - m_stateDB = OverlayDB(); - SecureTrieDB accountState(&m_stateDB); - accountState.init(); - - dev::eth::commit(_accounts, static_cast(m_stateDB), accountState); - h256 stateRoot = accountState.root(); - m_bc.reset(); - m_bc.reset(new MixBlockChain(m_dbPath, stateRoot)); - m_state = eth::State(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address()); - m_state.sync(bc()); - m_startState = m_state; - WriteGuard lx(x_executions); - m_executions.clear(); + WriteGuard l(x_state); + Guard fl(x_filtersWatches); + m_filters.clear(); + m_watches.clear(); + //LogFilter filter; + //m_filters.insert(std::make_pair(filter.sha3(), filter)); + //m_watches.insert(std::make_pair(0, ClientWatch(filter.sha3(), Reaping::Automatic))); + + m_stateDB = OverlayDB(); + SecureTrieDB accountState(&m_stateDB); + accountState.init(); + + dev::eth::commit(_accounts, static_cast(m_stateDB), accountState); + h256 stateRoot = accountState.root(); + m_bc.reset(); + m_bc.reset(new MixBlockChain(m_dbPath, stateRoot)); + m_state = eth::State(m_stateDB, BaseState::PreExisting, KeyPair(_miner).address()); + m_state.sync(bc()); + m_startState = m_state; + WriteGuard lx(x_executions); + m_executions.clear(); } Transaction MixClient::replaceGas(Transaction const& _t, u256 const& _gas, Secret const& _secret) { - Transaction ret; - if (_secret) - { - if (_t.isCreation()) - ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce(), _secret); - else - ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce(), _secret); - } - else - { - if (_t.isCreation()) - ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce()); - else - ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce()); - ret.forceSender(_t.safeSender()); - } - return ret; + Transaction ret; + if (_secret) + { + if (_t.isCreation()) + ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce(), _secret); + else + ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce(), _secret); + } + else + { + if (_t.isCreation()) + ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.data(), _t.nonce()); + else + ret = Transaction(_t.value(), _t.gasPrice(), _gas, _t.receiveAddress(), _t.data(), _t.nonce()); + ret.forceSender(_t.safeSender()); + } + return ret; } void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _call, bool _gasAuto, Secret const& _secret) { - Transaction t = _gasAuto ? replaceGas(_t, m_state.gasLimitRemaining()) : _t; + Transaction t = _gasAuto ? replaceGas(_t, m_state.gasLimitRemaining()) : _t; // do debugging run first - LastHashes lastHashes(256); - lastHashes[0] = bc().numberHash(bc().number()); - for (unsigned i = 1; i < 256; ++i) - lastHashes[i] = lastHashes[i - 1] ? bc().details(lastHashes[i - 1]).parent : h256(); - - State execState = _state; - execState.addBalance(t.sender(), t.gas() * t.gasPrice()); //give it enough balance for gas estimation - Executive execution(execState, lastHashes, 0); - execution.initialize(t); - execution.execute(); - std::vector machineStates; - std::vector levels; - std::vector codes; - std::map codeIndexes; - std::vector data; - std::map dataIndexes; - bytes const* lastCode = nullptr; - bytesConstRef const* lastData = nullptr; - unsigned codeIndex = 0; - unsigned dataIndex = 0; - auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, void* voidVM, void const* voidExt) - { - VM& vm = *static_cast(voidVM); - ExtVM const& ext = *static_cast(voidExt); - if (lastCode == nullptr || lastCode != &ext.code) - { - auto const& iter = codeIndexes.find(&ext.code); - if (iter != codeIndexes.end()) - codeIndex = iter->second; - else - { - codeIndex = codes.size(); - codes.push_back(MachineCode({ext.myAddress, ext.code})); - codeIndexes[&ext.code] = codeIndex; - } - lastCode = &ext.code; - } - - if (lastData == nullptr || lastData != &ext.data) - { - auto const& iter = dataIndexes.find(&ext.data); - if (iter != dataIndexes.end()) - dataIndex = iter->second; - else - { - dataIndex = data.size(); - data.push_back(ext.data.toBytes()); - dataIndexes[&ext.data] = dataIndex; - } - lastData = &ext.data; - } - - if (levels.size() < ext.depth) - levels.push_back(machineStates.size() - 1); - else - levels.resize(ext.depth); - - machineStates.emplace_back(MachineState({steps, vm.curPC(), inst, newMemSize, vm.gas(), - vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels, codeIndex, dataIndex})); - }; - - execution.go(onOp); - execution.finalize(); - dev::eth::ExecutionResult er = execution.executionResult(); - - switch (er.excepted) - { - case TransactionException::None: - break; - case TransactionException::NotEnoughCash: - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Insufficient balance for contract deployment")); - case TransactionException::OutOfGasBase: - case TransactionException::OutOfGas: - BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas")); - case TransactionException::BlockGasLimitReached: - BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Block gas limit reached")); - case TransactionException::OutOfStack: - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Out of stack")); - case TransactionException::StackUnderflow: - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Stack underflow")); - //these should not happen in mix - case TransactionException::Unknown: - case TransactionException::BadInstruction: - case TransactionException::BadJumpDestination: - case TransactionException::InvalidSignature: - case TransactionException::InvalidNonce: - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Internal execution error")); - }; - - ExecutionResult d; + LastHashes lastHashes(256); + lastHashes[0] = bc().numberHash(bc().number()); + for (unsigned i = 1; i < 256; ++i) + lastHashes[i] = lastHashes[i - 1] ? bc().details(lastHashes[i - 1]).parent : h256(); + + State execState = _state; + execState.addBalance(t.sender(), t.gas() * t.gasPrice()); //give it enough balance for gas estimation + Executive execution(execState, lastHashes, 0); + execution.initialize(t); + execution.execute(); + std::vector machineStates; + std::vector levels; + std::vector codes; + std::map codeIndexes; + std::vector data; + std::map dataIndexes; + bytes const* lastCode = nullptr; + bytesConstRef const* lastData = nullptr; + unsigned codeIndex = 0; + unsigned dataIndex = 0; + auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, void* voidVM, void const* voidExt) + { + VM& vm = *static_cast(voidVM); + ExtVM const& ext = *static_cast(voidExt); + if (lastCode == nullptr || lastCode != &ext.code) + { + auto const& iter = codeIndexes.find(&ext.code); + if (iter != codeIndexes.end()) + codeIndex = iter->second; + else + { + codeIndex = codes.size(); + codes.push_back(MachineCode({ext.myAddress, ext.code})); + codeIndexes[&ext.code] = codeIndex; + } + lastCode = &ext.code; + } + + if (lastData == nullptr || lastData != &ext.data) + { + auto const& iter = dataIndexes.find(&ext.data); + if (iter != dataIndexes.end()) + dataIndex = iter->second; + else + { + dataIndex = data.size(); + data.push_back(ext.data.toBytes()); + dataIndexes[&ext.data] = dataIndex; + } + lastData = &ext.data; + } + + if (levels.size() < ext.depth) + levels.push_back(machineStates.size() - 1); + else + levels.resize(ext.depth); + + machineStates.emplace_back(MachineState({steps, vm.curPC(), inst, newMemSize, vm.gas(), + vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels, codeIndex, dataIndex})); + }; + + execution.go(onOp); + execution.finalize(); + dev::eth::ExecutionResult er = execution.executionResult(); + + switch (er.excepted) + { + case TransactionException::None: + break; + case TransactionException::NotEnoughCash: + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Insufficient balance for contract deployment")); + case TransactionException::OutOfGasBase: + case TransactionException::OutOfGas: + BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas")); + case TransactionException::BlockGasLimitReached: + BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Block gas limit reached")); + case TransactionException::OutOfStack: + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Out of stack")); + case TransactionException::StackUnderflow: + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Stack underflow")); + //these should not happen in mix + case TransactionException::Unknown: + case TransactionException::BadInstruction: + case TransactionException::BadJumpDestination: + case TransactionException::InvalidSignature: + case TransactionException::InvalidNonce: + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Internal execution error")); + }; + + ExecutionResult d; d.inputParameters = t.data(); - d.result = execution.executionResult(); - d.machineStates = machineStates; - d.executionCode = std::move(codes); - d.transactionData = std::move(data); - d.address = _t.receiveAddress(); - d.sender = _t.sender(); - d.value = _t.value(); - d.gasUsed = er.gasUsed + er.gasRefunded + c_callStipend; - if (_t.isCreation()) - d.contractAddress = right160(sha3(rlpList(_t.sender(), _t.nonce()))); - if (!_call) - d.transactionIndex = m_state.pending().size(); - d.executonIndex = m_executions.size(); + d.result = execution.executionResult(); + d.machineStates = machineStates; + d.executionCode = std::move(codes); + d.transactionData = std::move(data); + d.address = _t.receiveAddress(); + d.sender = _t.sender(); + d.value = _t.value(); + d.gasUsed = er.gasUsed + er.gasRefunded + c_callStipend; + if (_t.isCreation()) + d.contractAddress = right160(sha3(rlpList(_t.sender(), _t.nonce()))); + if (!_call) + d.transactionIndex = m_state.pending().size(); + d.executonIndex = m_executions.size(); // execute on a state - if (!_call) - { - t = _gasAuto ? replaceGas(_t, d.gasUsed, _secret) : _t; - er =_state.execute(lastHashes, t); - if (t.isCreation() && _state.code(d.contractAddress).empty()) - BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment")); - d.gasUsed = er.gasUsed + er.gasRefunded + er.gasForDeposit + c_callStipend; - // collect watches - h256Set changed; - Guard l(x_filtersWatches); - for (std::pair& i: m_filters) - if ((unsigned)i.second.filter.latest() > bc().number()) - { - // acceptable number. - auto m = i.second.filter.matches(_state.receipt(_state.pending().size() - 1)); - if (m.size()) - { - // filter catches them - for (LogEntry const& l: m) - i.second.changes.push_back(LocalisedLogEntry(l, bc().number() + 1)); - changed.insert(i.first); - } - } - changed.insert(dev::eth::PendingChangedFilter); - noteChanged(changed); - } - WriteGuard l(x_executions); - m_executions.emplace_back(std::move(d)); + if (!_call) + { + t = _gasAuto ? replaceGas(_t, d.gasUsed, _secret) : _t; + er = _state.execute(lastHashes, t); + if (t.isCreation() && _state.code(d.contractAddress).empty()) + BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment")); + d.gasUsed = er.gasUsed + er.gasRefunded + er.gasForDeposit + c_callStipend; + // collect watches + h256Set changed; + Guard l(x_filtersWatches); + LocalisedLogEntries logs; + //for (unsigned i = 0; i < _state.pending().size(); ++i) + //{ + TransactionReceipt const& tr = _state.receipt(_state.pending().size() - 1); + + auto trHash = _state.pending().at(_state.pending().size() - 1).sha3(); + //for (std::pair& installedFilter: m_filters) + //{ + LogEntries le = tr.log(); // installedFilter.second.filter.matches(tr); + if (le.size()) + for (unsigned j = 0; j < le.size(); ++j) + logs.insert(logs.begin(), LocalisedLogEntry(le[j], bc().number() + 1, trHash)); + //} + //} + + /*if ((unsigned)i.second.filter.latest() > bc().number()) + { + // acceptable number. + auto m = i.second.filter.matches(_state.receipt(_state.pending().size() - 1)); + if (m.size()) + { + // filter catches them + for (LogEntry const& l: m) + i.second.changes.push_back(LocalisedLogEntry(l, bc().number() + 1)); + changed.insert(i.first); + } + }*/ + changed.insert(dev::eth::PendingChangedFilter); + d.logs = logs; + //noteChanged(changed); + } + WriteGuard l(x_executions); + m_executions.emplace_back(std::move(d)); } void MixClient::mine() { - WriteGuard l(x_state); - m_state.commitToMine(bc()); - m_state.completeMine(0); - bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidNonce); - m_state.sync(bc()); - m_startState = m_state; - h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter }; - noteChanged(changed); + WriteGuard l(x_state); + m_state.commitToMine(bc()); + m_state.completeMine(0); + bc().import(m_state.blockData(), m_state.db(), ImportRequirements::Default & ~ImportRequirements::ValidNonce); + m_state.sync(bc()); + m_startState = m_state; + h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter }; + //noteChanged(changed); } ExecutionResult MixClient::lastExecution() const { - ReadGuard l(x_executions); - return m_executions.empty() ? ExecutionResult() : m_executions.back(); + ReadGuard l(x_executions); + return m_executions.empty() ? ExecutionResult() : m_executions.back(); } ExecutionResult MixClient::execution(unsigned _index) const { - ReadGuard l(x_executions); - return m_executions.at(_index); + ReadGuard l(x_executions); + return m_executions.at(_index); } State MixClient::asOf(h256 const& _block) const { - ReadGuard l(x_state); - return State(m_stateDB, bc(), _block); + ReadGuard l(x_state); + return State(m_stateDB, bc(), _block); } void MixClient::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, bool _gasAuto) { - WriteGuard l(x_state); - u256 n = m_state.transactionsFrom(toAddress(_secret)); - Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); - executeTransaction(t, m_state, false, _gasAuto, _secret); + WriteGuard l(x_state); + u256 n = m_state.transactionsFrom(toAddress(_secret)); + Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); + executeTransaction(t, m_state, false, _gasAuto, _secret); } Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice, bool _gasAuto) { - WriteGuard l(x_state); - u256 n = m_state.transactionsFrom(toAddress(_secret)); - eth::Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret); - executeTransaction(t, m_state, false, _gasAuto, _secret); - Address address = right160(sha3(rlpList(t.sender(), t.nonce()))); - return address; + WriteGuard l(x_state); + u256 n = m_state.transactionsFrom(toAddress(_secret)); + eth::Transaction t(_endowment, _gasPrice, _gas, _init, n, _secret); + executeTransaction(t, m_state, false, _gasAuto, _secret); + Address address = right160(sha3(rlpList(t.sender(), t.nonce()))); + return address; } dev::eth::ExecutionResult MixClient::call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, bool _gasAuto, FudgeFactor _ff) { - (void)_blockNumber; - State temp = asOf(eth::PendingBlock); - u256 n = temp.transactionsFrom(_from); - Transaction t(_value, _gasPrice, _gas, _dest, _data, n); - t.forceSender(_from); - if (_ff == FudgeFactor::Lenient) - temp.addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value())); - WriteGuard lw(x_state); //TODO: lock is required only for last execution state - executeTransaction(t, temp, true, _gasAuto); - return lastExecution().result; + (void)_blockNumber; + State temp = asOf(eth::PendingBlock); + u256 n = temp.transactionsFrom(_from); + Transaction t(_value, _gasPrice, _gas, _dest, _data, n); + t.forceSender(_from); + if (_ff == FudgeFactor::Lenient) + temp.addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value())); + WriteGuard lw(x_state); //TODO: lock is required only for last execution state + executeTransaction(t, temp, true, _gasAuto); + return lastExecution().result; } void MixClient::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) { - submitTransaction(_secret, _value, _dest, _data, _gas, _gasPrice, false); + submitTransaction(_secret, _value, _dest, _data, _gas, _gasPrice, false); } Address MixClient::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) { - return submitTransaction(_secret, _endowment, _init, _gas, _gasPrice, false); + return submitTransaction(_secret, _endowment, _init, _gas, _gasPrice, false); } dev::eth::ExecutionResult MixClient::call(Address const& _from, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, eth::FudgeFactor _ff) { - return call(_from, _value, _dest, _data, _gas, _gasPrice, _blockNumber, false, _ff); + return call(_from, _value, _dest, _data, _gas, _gasPrice, _blockNumber, false, _ff); } dev::eth::ExecutionResult MixClient::create(Address const& _from, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, BlockNumber _blockNumber, eth::FudgeFactor _ff) { - (void)_blockNumber; - u256 n; - State temp; - { - ReadGuard lr(x_state); - temp = asOf(eth::PendingBlock); - n = temp.transactionsFrom(_from); - } - Transaction t(_value, _gasPrice, _gas, _data, n); - t.forceSender(_from); - if (_ff == FudgeFactor::Lenient) - temp.addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value())); - WriteGuard lw(x_state); //TODO: lock is required only for last execution state - executeTransaction(t, temp, true, false); - return lastExecution().result; + (void)_blockNumber; + u256 n; + State temp; + { + ReadGuard lr(x_state); + temp = asOf(eth::PendingBlock); + n = temp.transactionsFrom(_from); + } + Transaction t(_value, _gasPrice, _gas, _data, n); + t.forceSender(_from); + if (_ff == FudgeFactor::Lenient) + temp.addBalance(_from, (u256)(t.gasRequired() * t.gasPrice() + t.value())); + WriteGuard lw(x_state); //TODO: lock is required only for last execution state + executeTransaction(t, temp, true, false); + return lastExecution().result; } -void MixClient::noteChanged(h256Set const& _filters) +/*void MixClient::noteChanged(h256Set const& _filters) { - for (auto& i: m_watches) - if (_filters.count(i.second.id)) - { - if (m_filters.count(i.second.id)) - i.second.changes += m_filters.at(i.second.id).changes; - else - i.second.changes.push_back(LocalisedLogEntry(SpecialLogEntry, 0)); - } - for (auto& i: m_filters) - i.second.changes.clear(); -} + for (auto& i: m_watches) + if (_filters.count(i.second.id)) + { + if (m_filters.count(i.second.id)) + i.second.changes += m_filters.at(i.second.id).changes; + else + i.second.changes.push_back(LocalisedLogEntry(SpecialLogEntry, 0)); + } + for (auto& i: m_filters) + i.second.changes.clear(); +}*/ eth::BlockInfo MixClient::blockInfo() const { - ReadGuard l(x_state); - return BlockInfo(bc().block()); + ReadGuard l(x_state); + return BlockInfo(bc().block()); } void MixClient::setAddress(Address _us) { - WriteGuard l(x_state); - m_state.setAddress(_us); + WriteGuard l(x_state); + m_state.setAddress(_us); } void MixClient::startMining() { - //no-op + //no-op } void MixClient::stopMining() { - //no-op + //no-op } bool MixClient::isMining() const { - return false; + return false; } uint64_t MixClient::hashrate() const { - return 0; + return 0; } eth::MiningProgress MixClient::miningProgress() const { - return eth::MiningProgress(); + return eth::MiningProgress(); } } diff --git a/mix/MixClient.h b/mix/MixClient.h index 852937634..ece603942 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -91,7 +91,7 @@ protected: private: void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call, bool _gasAuto, dev::Secret const& _secret = dev::Secret()); - void noteChanged(h256Set const& _filters); + //void noteChanged(h256Set const& _filters); dev::eth::Transaction replaceGas(dev::eth::Transaction const& _t, dev::u256 const& _gas, dev::Secret const& _secret = dev::Secret()); eth::State m_state; diff --git a/mix/QContractDefinition.cpp b/mix/QContractDefinition.cpp index 51b37e399..fe05e80be 100644 --- a/mix/QContractDefinition.cpp +++ b/mix/QContractDefinition.cpp @@ -39,8 +39,23 @@ QContractDefinition::QContractDefinition(QObject* _parent, dev::solidity::Contra else m_constructor = new QFunctionDefinition(parent); + std::vector found; + for (auto const& f: _contract->getDefinedFunctions()) + { + m_functions.append(new QFunctionDefinition(parent, f)); + found.push_back(f->getName()); + } + for (auto const& it: _contract->getInterfaceFunctions()) - m_functions.append(new QFunctionDefinition(parent, it.second)); + { + if (std::find(found.begin(), found.end(), it.second->getDeclaration().getName()) == found.end()) + m_functions.append(new QFunctionDefinition(parent, it.second)); + } + + + for (auto const& it: _contract->getEvents()) + m_events.append(new QFunctionDefinition(parent, it)); + } QFunctionDefinition const* QContractDefinition::getFunction(dev::FixedHash<4> _hash) const diff --git a/mix/QContractDefinition.h b/mix/QContractDefinition.h index ff0df1f15..f68133ab7 100644 --- a/mix/QContractDefinition.h +++ b/mix/QContractDefinition.h @@ -37,6 +37,7 @@ class QContractDefinition: public QBasicNodeDefinition Q_OBJECT Q_PROPERTY(QQmlListProperty functions READ functions CONSTANT) Q_PROPERTY(dev::mix::QFunctionDefinition* constructor READ constructor CONSTANT) + Q_PROPERTY(QQmlListProperty events READ events CONSTANT) public: QContractDefinition(QObject* _parent, solidity::ContractDefinition const* _contract); @@ -44,12 +45,19 @@ public: QQmlListProperty functions() const { return QQmlListProperty(const_cast(this), const_cast(this)->m_functions); } /// Get the constructor of the contract. QFunctionDefinition* constructor() const { return m_constructor; } + /// Get all the functions of the contract. QList const& functionsList() const { return m_functions; } /// Find function by hash, returns nullptr if not found QFunctionDefinition const* getFunction(dev::FixedHash<4> _hash) const; + /// Get events + QQmlListProperty events() const { return QQmlListProperty(const_cast(this), const_cast(this)->m_events); } + /// Get events + QList const& eventsList() const { return m_events; } + private: QList m_functions; QFunctionDefinition* m_constructor; + QList m_events; }; } diff --git a/mix/QFunctionDefinition.cpp b/mix/QFunctionDefinition.cpp index e6764d712..52d8ad30c 100644 --- a/mix/QFunctionDefinition.cpp +++ b/mix/QFunctionDefinition.cpp @@ -28,15 +28,41 @@ using namespace dev::solidity; using namespace dev::mix; -QFunctionDefinition::QFunctionDefinition(QObject* _parent, dev::solidity::FunctionTypePointer const& _f): QBasicNodeDefinition(_parent, &_f->getDeclaration()), m_hash(dev::sha3(_f->externalSignature())) +QFunctionDefinition::QFunctionDefinition(QObject* _parent, dev::solidity::FunctionTypePointer const& _f): QBasicNodeDefinition(_parent, &_f->getDeclaration()), m_hash(dev::sha3(_f->externalSignature())), + m_fullHash(dev::sha3(_f->externalSignature())) +{ + init(_f); +} + +QFunctionDefinition::QFunctionDefinition(QObject* _parent, ASTPointer const& _f): QBasicNodeDefinition(_parent, _f.get()), m_hash(dev::sha3(_f->externalSignature())), + m_fullHash(dev::sha3(_f->externalSignature())) +{ + + for (unsigned i = 0; i < _f->getParameters().size(); ++i) + m_parameters.append(new QVariableDeclaration(parent(), _f->getParameters().at(i))); + + for (unsigned i = 0; i < _f->getReturnParameters().size(); ++i) + m_returnParameters.append(new QVariableDeclaration(parent(), _f->getReturnParameters().at(i))); +} + +QFunctionDefinition::QFunctionDefinition(QObject* _parent, ASTPointer const& _e): QBasicNodeDefinition(_parent, _e.get()) +{ + for (unsigned i = 0; i < _e->getParameters().size(); ++i) + m_parameters.append(new QVariableDeclaration(parent(), _e->getParameters().at(i))); + FunctionTypePointer _f = std::make_shared(*_e); + m_hash = (FixedHash<4>)dev::sha3(_f->externalSignature(_e->getName())); + m_fullHash = dev::sha3(_f->externalSignature(_e->getName())); +} + +void QFunctionDefinition::init(dev::solidity::FunctionTypePointer _f) { auto paramNames = _f->getParameterNames(); auto paramTypes = _f->getParameterTypes(); auto returnNames = _f->getReturnParameterNames(); auto returnTypes = _f->getReturnParameterTypes(); for (unsigned i = 0; i < paramNames.size(); ++i) - m_parameters.append(new QVariableDeclaration(_parent, paramNames[i], paramTypes[i].get())); + m_parameters.append(new QVariableDeclaration(parent(), paramNames[i], paramTypes[i].get())); for (unsigned i = 0; i < returnNames.size(); ++i) - m_returnParameters.append(new QVariableDeclaration(_parent, returnNames[i], returnTypes[i].get())); + m_returnParameters.append(new QVariableDeclaration(parent(), returnNames[i], returnTypes[i].get())); } diff --git a/mix/QFunctionDefinition.h b/mix/QFunctionDefinition.h index 18f2d911b..a9c45ffcd 100644 --- a/mix/QFunctionDefinition.h +++ b/mix/QFunctionDefinition.h @@ -41,6 +41,10 @@ public: QFunctionDefinition(){} QFunctionDefinition(QObject* _parent): QBasicNodeDefinition(_parent) {} QFunctionDefinition(QObject* _parent, solidity::FunctionTypePointer const& _f); + QFunctionDefinition(QObject* _parent, solidity::ASTPointer const& _f); + QFunctionDefinition(QObject* _parent, solidity::ASTPointer const& _f); + /// Init members + void init(dev::solidity::FunctionTypePointer _f); /// Get all input parameters of this function. QList const& parametersList() const { return m_parameters; } /// Get all input parameters of this function as QML property. @@ -49,10 +53,13 @@ public: QList returnParameters() const { return m_returnParameters; } /// Get the hash of this function declaration on the contract ABI. FixedHash<4> hash() const { return m_hash; } + /// Get the full hash of this function declaration on the contract ABI. + FixedHash<32> fullHash() const { return m_fullHash; } private: int m_index; FixedHash<4> m_hash; + FixedHash<32> m_fullHash; QList m_parameters; QList m_returnParameters; void initQParameters(); diff --git a/mix/QVariableDeclaration.cpp b/mix/QVariableDeclaration.cpp index 3bbb0d523..4299e34ee 100644 --- a/mix/QVariableDeclaration.cpp +++ b/mix/QVariableDeclaration.cpp @@ -24,27 +24,32 @@ #include #include "CodeModel.h" +using namespace solidity; + namespace dev { namespace mix { -QVariableDeclaration::QVariableDeclaration(QObject* _parent, solidity::VariableDeclaration const* _v): - QBasicNodeDefinition(_parent, _v), +QVariableDeclaration::QVariableDeclaration(QObject* _parent, ASTPointer const _v): + QBasicNodeDefinition(_parent, _v.get()), m_type(new QSolidityType(this, CodeModel::nodeType(_v->getType().get()))) { + m_isIndexed = _v->isIndexed(); } -QVariableDeclaration::QVariableDeclaration(QObject* _parent, std::string const& _name, SolidityType const& _type): +QVariableDeclaration::QVariableDeclaration(QObject* _parent, std::string const& _name, SolidityType const& _type, bool _isIndexed): QBasicNodeDefinition(_parent, _name), m_type(new QSolidityType(_parent, _type)) { + m_isIndexed = _isIndexed; } -QVariableDeclaration::QVariableDeclaration(QObject* _parent, std::string const& _name, solidity::Type const* _type): +QVariableDeclaration::QVariableDeclaration(QObject* _parent, std::string const& _name, solidity::Type const* _type, bool _isIndexed): QBasicNodeDefinition(_parent, _name), m_type(new QSolidityType(this, CodeModel::nodeType(_type))) { + m_isIndexed = _isIndexed; } QSolidityType::QSolidityType(QObject* _parent, SolidityType const& _type): diff --git a/mix/QVariableDeclaration.h b/mix/QVariableDeclaration.h index 4309550b2..85c719987 100644 --- a/mix/QVariableDeclaration.h +++ b/mix/QVariableDeclaration.h @@ -21,6 +21,7 @@ #include #include +#include #include "QBasicNodeDefinition.h" #include "SolidityType.h" @@ -82,14 +83,16 @@ class QVariableDeclaration: public QBasicNodeDefinition public: QVariableDeclaration() {} - QVariableDeclaration(QObject* _parent, solidity::VariableDeclaration const* _v); - QVariableDeclaration(QObject* _parent, std::string const& _name, SolidityType const& _type); - QVariableDeclaration(QObject* _parent, std::string const& _name, solidity::Type const* _type); + QVariableDeclaration(QObject* _parent, solidity::ASTPointer const _v); + QVariableDeclaration(QObject* _parent, std::string const& _name, SolidityType const& _type, bool _isIndexed = false); + QVariableDeclaration(QObject* _parent, std::string const& _name, solidity::Type const* _type, bool _isIndexed = false); QSolidityType* type() const { return m_type; } void setType(QSolidityType* _type) { m_type = _type; } + bool isIndexed() { return m_isIndexed; } private: QSolidityType* m_type; + bool m_isIndexed; }; diff --git a/mix/qml/Block.qml b/mix/qml/Block.qml index e331dc6a6..c3ce7865a 100644 --- a/mix/qml/Block.qml +++ b/mix/qml/Block.qml @@ -121,22 +121,36 @@ ColumnLayout clip: true } + Label + { + id: logs + width: logsWidth + text: { + if (index >= 0 && transactions.get(index).logs) + { + for (var k in transactions.get(index).logs) + { + console.log("_________________________") + console.log(JSON.stringify(transactions.get(index).logs[k])) + console.log("_________________________") + } + return transactions.get(index).logs.length + } + else + return 0 + } + } + Button { id: debug - width: logsWidth + width: debugActionWidth text: "debug" onClicked: { clientModel.debugRecord(transactions.get(index).recordIndex); } } - - Label - { - id: logs - width: logsWidth - } } } } diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml index 6e87ed52d..6098ec035 100644 --- a/mix/qml/BlockChain.qml +++ b/mix/qml/BlockChain.qml @@ -30,8 +30,9 @@ Column { property int statusWidth: 50 property int fromWidth: 100 property int toWidth: 250 - property int valueWidth: 100 + property int valueWidth: 50 property int logsWidth: 50 + property int debugActionWidth: 50 Row { @@ -62,6 +63,11 @@ Column { text: "Logs" width: logsWidth } + Label + { + text: "Action" + width: debugActionWidth + } } Rectangle @@ -253,6 +259,8 @@ Column { blockModel.getTransaction(blockIndex, trIndex).returned = _r.returned; tr.recordIndex = _r.recordIndex; blockModel.getTransaction(blockIndex, trIndex).recordIndex = _r.recordIndex; + tr.logs = _r.logs; + blockModel.getTransaction(blockIndex, trIndex).logs = _r.logs; return; } } @@ -270,6 +278,7 @@ Column { itemTr.value = QEtherHelper.createEther(_r.value, QEther.Wei) itemTr.sender = _r.sender itemTr.recordIndex = _r.recordIndex + itemTr.logs = _r.logs model.blocks[model.blocks.length - 1].transactions.push(itemTr) blockModel.appendTransaction(itemTr) From 6e6ebc60371c09b08c2dbd6a6411d6f693ff8a4e Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 8 Jun 2015 13:42:39 +0200 Subject: [PATCH 03/40] ScenarioExecution.qml ux design --- mix/qml.qrc | 1 + mix/qml/Block.qml | 169 +++++++++------ mix/qml/BlockChain.qml | 334 +++++++++++++++++------------ mix/qml/ScenarioButton.qml | 62 ++++++ mix/qml/ScenarioExecution.qml | 7 +- mix/qml/ScenarioLoader.qml | 27 ++- mix/qml/StateListModel.qml | 5 +- mix/qml/img/duplicateIcon.png | Bin 0 -> 1020 bytes mix/qml/img/duplicateIcon@2x.png | Bin 0 -> 2326 bytes mix/qml/img/newIcon.png | Bin 0 -> 801 bytes mix/qml/img/newIcon@2x.png | Bin 0 -> 1768 bytes mix/qml/img/recycle-discard.png | Bin 0 -> 723 bytes mix/qml/img/recycle-discard@2x.png | Bin 0 -> 1568 bytes mix/qml/img/recycle-icon.png | Bin 0 -> 697 bytes mix/qml/img/recycle-icon@2x.png | Bin 0 -> 1435 bytes mix/qml/img/recycle-keep.png | Bin 0 -> 904 bytes mix/qml/img/recycle-keep@2x.png | Bin 0 -> 2141 bytes mix/qml/img/restoreIcon.png | Bin 0 -> 1124 bytes mix/qml/img/restoreIcon@2x.png | Bin 0 -> 2447 bytes mix/qml/img/saveIcon.png | Bin 0 -> 1068 bytes mix/qml/img/saveIcon@2x.png | Bin 0 -> 2359 bytes mix/res.qrc | 12 ++ 22 files changed, 409 insertions(+), 208 deletions(-) create mode 100644 mix/qml/ScenarioButton.qml create mode 100644 mix/qml/img/duplicateIcon.png create mode 100644 mix/qml/img/duplicateIcon@2x.png create mode 100644 mix/qml/img/newIcon.png create mode 100644 mix/qml/img/newIcon@2x.png create mode 100644 mix/qml/img/recycle-discard.png create mode 100644 mix/qml/img/recycle-discard@2x.png create mode 100644 mix/qml/img/recycle-icon.png create mode 100644 mix/qml/img/recycle-icon@2x.png create mode 100644 mix/qml/img/recycle-keep.png create mode 100644 mix/qml/img/recycle-keep@2x.png create mode 100644 mix/qml/img/restoreIcon.png create mode 100644 mix/qml/img/restoreIcon@2x.png create mode 100644 mix/qml/img/saveIcon.png create mode 100644 mix/qml/img/saveIcon@2x.png diff --git a/mix/qml.qrc b/mix/qml.qrc index 0227b4efd..16bb01b83 100644 --- a/mix/qml.qrc +++ b/mix/qml.qrc @@ -68,5 +68,6 @@ qml/BlockChain.qml qml/ScenarioExecution.qml qml/ScenarioLoader.qml + qml/ScenarioButton.qml diff --git a/mix/qml/Block.qml b/mix/qml/Block.qml index c3ce7865a..d3775ea5c 100644 --- a/mix/qml/Block.qml +++ b/mix/qml/Block.qml @@ -10,25 +10,40 @@ import "." ColumnLayout { + id: root property variant transactions property string status property int number - Rectangle - { - width: parent.width - height: 50 - anchors.left: parent.left - anchors.leftMargin: statusWidth - Label { - text: - { - if (status === "mined") - return qsTr("BLOCK") + " " + number - else - return qsTr("BLOCK") + " pending" - } + property int blockWidth: Layout.preferredWidth - statusWidth - horizontalMargin + property int horizontalMargin: 10 + property int trHeight: 30 + spacing: 0 + RowLayout + { + Layout.preferredHeight: trHeight + Layout.preferredWidth: blockWidth + id: rowHeader + Rectangle + { + color: "#DEDCDC" + Layout.preferredWidth: blockWidth + Layout.preferredHeight: trHeight + radius: 4 anchors.left: parent.left + anchors.leftMargin: statusWidth + 5 + Label { + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: horizontalMargin + text: + { + if (status === "mined") + return qsTr("BLOCK") + " " + number + else + return qsTr("BLOCK") + " pending" + } + } } } @@ -36,57 +51,80 @@ ColumnLayout { id: transactionRepeater model: transactions - Row + + RowLayout { - height: 50 + Layout.preferredHeight: trHeight Rectangle { id: trSaveStatus + Layout.preferredWidth: statusWidth + Layout.preferredHeight: trHeight color: "transparent" - CheckBox + property bool saveStatus + + Image { + id: saveStatusImage + source: "qrc:/qml/img/recycle-discard@2x.png" + width: statusWidth + fillMode: Image.PreserveAspectFit + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + } + + Component.onCompleted: { - id: saveStatus - checked: { - if (index >= 0) - return transactions.get(index).saveStatus - else - return true - } - onCheckedChanged: + if (index >= 0) + saveStatus = transactions.get(index).saveStatus + } + + onSaveStatusChanged: + { + if (saveStatus) + saveStatusImage.source = "qrc:/qml/img/recycle-keep@2x.png" + else + saveStatusImage.source = "qrc:/qml/img/recycle-discard@2x.png" + + if (index >= 0) + transactions.get(index).saveStatus = saveStatus + } + + MouseArea { + id: statusMouseArea + anchors.fill: parent + onClicked: { - if (index >= 0) - transactions.get(index).saveStatus = checked + parent.saveStatus = !parent.saveStatus } } } Rectangle { - width: parent.width - height: 50 - color: "#cccccc" - radius: 4 - Row + Layout.preferredWidth: blockWidth + Layout.preferredHeight: parent.height + color: "#DEDCDC" + RowLayout { - Label - { - id: status - width: statusWidth - } - Label + anchors.verticalCenter: parent.verticalCenter + spacing: cellSpacing + Text { id: hash - width: fromWidth + anchors.left: parent.left + anchors.leftMargin: horizontalMargin + Layout.preferredWidth: fromWidth + elide: Text.ElideRight + maximumLineCount: 1 text: { if (index >= 0) return transactions.get(index).sender else return "" } - - clip: true } - Label + + Text { id: func text: { @@ -95,9 +133,9 @@ ColumnLayout else return "" } - - width: toWidth - clip: true + elide: Text.ElideRight + maximumLineCount: 1 + Layout.preferredWidth: toWidth } function userFrienldyToken(value) @@ -108,43 +146,52 @@ ColumnLayout return value } - Label + Text { id: returnValue - width: valueWidth + elide: Text.ElideRight + maximumLineCount: 1 + Layout.preferredWidth: valueWidth text: { if (index >= 0 && transactions.get(index).returned) return transactions.get(index).returned else return "" } - clip: true } - Label + Rectangle { - id: logs + Layout.preferredWidth: logsWidth + Layout.preferredHeight: trHeight - 10 width: logsWidth - text: { - if (index >= 0 && transactions.get(index).logs) - { - for (var k in transactions.get(index).logs) + color: "transparent" + Text + { + id: logs + anchors.left: parent.left + anchors.leftMargin: 10 + text: { + if (index >= 0 && transactions.get(index).logs && transactions.get(index).logs.count) { - console.log("_________________________") - console.log(JSON.stringify(transactions.get(index).logs[k])) - console.log("_________________________") + for (var k = 0; k < transactions.get(index).logs.count; k++) + { + /*console.log("_________________________") + console.log(JSON.stringify(transactions.get(index).logs[k])) + console.log("_________________________")*/ + } + return transactions.get(index).logs.count } - return transactions.get(index).logs.length + else + return "" } - else - return 0 } } Button { id: debug - width: debugActionWidth + Layout.preferredWidth: debugActionWidth text: "debug" onClicked: { diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml index 6098ec035..2fc78b0b1 100644 --- a/mix/qml/BlockChain.qml +++ b/mix/qml/BlockChain.qml @@ -11,91 +11,126 @@ import "js/TransactionHelper.js" as TransactionHelper import "js/QEtherHelper.js" as QEtherHelper import "." -Column { +ColumnLayout { id: blockChainPanel property variant model - spacing: 5 + spacing: 0 + property int previousWidth + onWidthChanged: + { + + if (width <= 630 || previousWidth <= 630) + { + fromWidth = 100 + toWidth = 100 + valueWidth = 200 + } + else + { + var diff = (width - previousWidth) / 3; + fromWidth = fromWidth + diff < 100 ? 100 : fromWidth + diff + toWidth = toWidth + diff < 100 ? 100 : toWidth + diff + valueWidth = valueWidth + diff < 200 ? 200 : valueWidth + diff + } + previousWidth = width + } function load(scenario) { - if (!scenario) return; model = scenario blockModel.clear() for (var b in model.blocks) blockModel.append(model.blocks[b]) + previousWidth = width } - property int statusWidth: 50 + property int statusWidth: 30 property int fromWidth: 100 - property int toWidth: 250 - property int valueWidth: 50 + property int toWidth: 100 + property int valueWidth: 200 property int logsWidth: 50 property int debugActionWidth: 50 + property int horizontalMargin: 10 + property int cellSpacing: 10 - Row + RowLayout { id: header - width: parent.width - Label - { - text: "Status" - width: statusWidth + spacing: 0 + Layout.preferredHeight: 25 + Image { + id: debugImage + source: "qrc:/qml/img/recycle-icon@2x.png" + Layout.preferredWidth: statusWidth + Layout.preferredHeight: 25 + fillMode: Image.PreserveAspectFit } - Label + Rectangle { - text: "From" - width: fromWidth + Layout.preferredWidth: fromWidth + cellSpacing + Label + { + anchors.verticalCenter: parent.verticalCenter + text: "From" + anchors.left: parent.left + anchors.leftMargin: horizontalMargin + 5 + } } Label { text: "To" - width: toWidth + Layout.preferredWidth: toWidth + cellSpacing } Label { text: "Value" - width: valueWidth + Layout.preferredWidth: valueWidth + cellSpacing } Label { text: "Logs" - width: logsWidth + Layout.preferredWidth: logsWidth + cellSpacing } Label { text: "Action" - width: debugActionWidth + Layout.preferredWidth: debugActionWidth } } Rectangle { - width: parent.width - height: 500 + Layout.preferredHeight: 500 + Layout.preferredWidth: parent.width + //height: 500 border.color: "#cccccc" border.width: 2 color: "white" ScrollView { - width: parent.width - height: parent.height + id: blockChainScrollView + anchors.fill: parent + anchors.topMargin: 10 ColumnLayout { + id: blockChainLayout + width: parent.width + spacing: 10 Repeater // List of blocks { id: blockChainRepeater - width: parent.width model: blockModel Block { - height: + Layout.preferredWidth: blockChainScrollView.width + Layout.preferredHeight: { if (index >= 0) - return 50 + 50 * blockModel.get(index).transactions.length + return 30 + 30 * blockModel.get(index).transactions.count else - return 0 + return 50 } transactions: @@ -143,8 +178,6 @@ Column { function removeTransaction(blockIndex, trIndex) { - console.log(blockIndex) - console.log(trIndex) blockModel.get(blockIndex).transactions.remove(trIndex) } @@ -160,139 +193,174 @@ Column { function getTransaction(block, tr) { - return blockModel.get(block - 1).transactions.get(tr) + return blockModel.get(block).transactions.get(tr) + } + + function setTransaction(blockIndex, trIndex, tr) + { + blockModel.get(blockIndex).transactions.set(trIndex, tr) + } + + function setTransactionProperty(blockIndex, trIndex, propertyName, value) + { + blockModel.get(blockIndex).transactions.set(trIndex, { propertyName: value }) } } - RowLayout + Rectangle { - width: parent.width - Button { - id: rebuild - text: qsTr("Rebuild") - onClicked: - { - for (var j = 0; j < model.blocks.length; j++) + Layout.preferredWidth: parent.width + RowLayout + { + width: parent.width + anchors.top: parent.top + anchors.topMargin: 10 + ScenarioButton { + id: rebuild + text: qsTr("Rebuild") + onClicked: { - for (var k = 0; k < model.blocks[j].transactions.length; k++) + for (var j = 0; j < model.blocks.length; j++) { - if (!blockModel.get(j).transactions.get(k).saveStatus) + for (var k = 0; k < model.blocks[j].transactions.length; k++) { - model.blocks[j].transactions.splice(k, 1) - blockModel.removeTransaction(j, k) - if (model.blocks[j].transactions.length === 0) + if (!blockModel.get(j).transactions.get(k).saveStatus) { - model.blocks[j].splice(j, 1); - blockModel.removeBlock(j); + model.blocks[j].transactions.splice(k, 1) + blockModel.removeTransaction(j, k) + if (model.blocks[j].transactions.length === 0) + { + model.blocks.splice(j, 1); + blockModel.removeBlock(j); + } } } } + clientModel.setupScenario(model); } - clientModel.setupScenario(model); - } - } - Button { - id: addTransaction - text: qsTr("Add Transaction") - onClicked: - { - var lastBlock = model.blocks[model.blocks.length - 1]; - if (lastBlock.status === "mined") - model.blocks.push(projectModel.stateListModel.createEmptyBlock()); - var item = TransactionHelper.defaultTransaction() - transactionDialog.stateAccounts = model.accounts - transactionDialog.open(model.blocks[model.blocks.length - 1].transactions.length, model.blocks.length - 1, item) + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/recycle-icon@2x.png" } - } - Button { - id: addBlockBtn - text: qsTr("Add Block") - onClicked: - { - var lastBlock = model.blocks[model.blocks.length - 1] - if (lastBlock.status === "pending") - clientModel.mine() - else - addNewBlock() - } - - function addNewBlock() - { - var block = projectModel.stateListModel.createEmptyBlock() - model.blocks.push(block) - blockModel.appendBlock(block) + ScenarioButton { + id: addTransaction + text: qsTr("Add Transaction") + onClicked: + { + var lastBlock = model.blocks[model.blocks.length - 1]; + if (lastBlock.status === "mined") + model.blocks.push(projectModel.stateListModel.createEmptyBlock()); + var item = TransactionHelper.defaultTransaction() + transactionDialog.stateAccounts = model.accounts + transactionDialog.open(model.blocks[model.blocks.length - 1].transactions.length, model.blocks.length - 1, item) + } + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/recycle-icon@2x.png" } - } - Connections - { - target: clientModel - onNewBlock: - { - if (!clientModel.running) + ScenarioButton { + id: addBlockBtn + text: qsTr("Add Block") + onClicked: { var lastBlock = model.blocks[model.blocks.length - 1] - lastBlock.status = "mined" - lastBlock.number = model.blocks.length - var lastB = blockModel.get(model.blocks.length - 1) - lastB.status = "mined" - lastB.number = model.blocks.length - addBlockBtn.addNewBlock() + if (lastBlock.status === "pending") + clientModel.mine() + else + addNewBlock() } + + function addNewBlock() + { + var block = projectModel.stateListModel.createEmptyBlock() + model.blocks.push(block) + blockModel.appendBlock(block) + } + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/recycle-icon@2x.png" } - onStateCleared: - { - } - onNewRecord: + + Connections { - var blockIndex = _r.transactionIndex.split(":")[0] - var trIndex = _r.transactionIndex.split(":")[1] - if (parseInt(blockIndex) <= model.blocks.length) + target: clientModel + onNewBlock: { - var item = model.blocks[parseInt(blockIndex) - 1]; - if (parseInt(trIndex) <= item.transactions.length) + if (!clientModel.running) { - var tr = item.transactions[parseInt(trIndex)]; - tr.returned = _r.returned; - blockModel.getTransaction(blockIndex, trIndex).returned = _r.returned; - tr.recordIndex = _r.recordIndex; - blockModel.getTransaction(blockIndex, trIndex).recordIndex = _r.recordIndex; - tr.logs = _r.logs; - blockModel.getTransaction(blockIndex, trIndex).logs = _r.logs; - return; + var lastBlock = model.blocks[model.blocks.length - 1] + lastBlock.status = "mined" + lastBlock.number = model.blocks.length + var lastB = blockModel.get(model.blocks.length - 1) + lastB.status = "mined" + lastB.number = model.blocks.length + addBlockBtn.addNewBlock() } } + onStateCleared: + { + } + onNewRecord: + { + var blockIndex = parseInt(_r.transactionIndex.split(":")[0]) - 1 + var trIndex = parseInt(_r.transactionIndex.split(":")[1]) + if (blockIndex <= model.blocks.length) + { + var item = model.blocks[blockIndex] + if (trIndex <= item.transactions.length) + { + var tr = item.transactions[trIndex] + tr.returned = _r.returned + tr.recordIndex = _r.recordIndex + tr.logs = _r.logs + var trModel = blockModel.getTransaction(blockIndex, trIndex) + trModel.returned = _r.returned + trModel.recordIndex = _r.recordIndex + trModel.logs = _r.logs + blockModel.setTransaction(blockIndex, trIndex, trModel) + return; + } + } - // tr is not in the list. coming from JavaScript - var itemTr = TransactionHelper.defaultTransaction() - itemTr.functionId = _r.function - itemTr.contractId = _r.contract - itemTr.gasAuto = true - itemTr.parameters = _r.parameters - itemTr.isContractCreation = itemTr.functionId === itemTr.contractId - itemTr.label = _r.label - itemTr.isFunctionCall = itemTr.functionId !== "" - itemTr.returned = _r.returned - itemTr.value = QEtherHelper.createEther(_r.value, QEther.Wei) - itemTr.sender = _r.sender - itemTr.recordIndex = _r.recordIndex - itemTr.logs = _r.logs - - model.blocks[model.blocks.length - 1].transactions.push(itemTr) - blockModel.appendTransaction(itemTr) - } - onMiningComplete: - { + // tr is not in the list. coming from JavaScript + var itemTr = TransactionHelper.defaultTransaction() + itemTr.saveStatus = false + itemTr.functionId = _r.function + itemTr.contractId = _r.contract + itemTr.gasAuto = true + itemTr.parameters = _r.parameters + itemTr.isContractCreation = itemTr.functionId === itemTr.contractId + itemTr.label = _r.label + itemTr.isFunctionCall = itemTr.functionId !== "" + itemTr.returned = _r.returned + itemTr.value = QEtherHelper.createEther(_r.value, QEther.Wei) + itemTr.sender = _r.sender + itemTr.recordIndex = _r.recordIndex + itemTr.logs = _r.logs + model.blocks[model.blocks.length - 1].transactions.push(itemTr) + blockModel.appendTransaction(itemTr) + } + onMiningComplete: + { + } } - } - Button { - id: newAccount - text: qsTr("New Account") - onClicked: { - model.accounts.push(projectModel.stateListModel.newAccount("1000000", QEther.Ether)) + ScenarioButton { + id: newAccount + text: qsTr("New Account") + onClicked: { + model.accounts.push(projectModel.stateListModel.newAccount("1000000", QEther.Ether)) + } + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/recycle-icon@2x.png" } } } diff --git a/mix/qml/ScenarioButton.qml b/mix/qml/ScenarioButton.qml new file mode 100644 index 000000000..e8884cc2e --- /dev/null +++ b/mix/qml/ScenarioButton.qml @@ -0,0 +1,62 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Layouts 1.0 +import QtQuick.Controls.Styles 1.1 + +Rectangle { + id: buttonActionContainer + property string text + property string buttonShortcut + property string sourceImg + signal clicked + + Rectangle { + id: contentRectangle + anchors.fill: parent + border.color: "#cccccc" + border.width: 1 + radius: 4 + Image { + id: debugImage + anchors { + centerIn: parent + bottomMargin: debugImg.pressed ? 0 : 1; + topMargin: debugImg.pressed ? 1 : 0; + } + source: sourceImg + fillMode: Image.PreserveAspectFit + height: 30 + } + + Button { + anchors.fill: parent + id: debugImg + action: buttonAction + style: ButtonStyle { + background: Rectangle { + color: "transparent" + } + } + } + + Action { + id: buttonAction + shortcut: buttonShortcut + onTriggered: { + buttonActionContainer.clicked(); + } + } + } + + Rectangle + { + anchors.top: contentRectangle.bottom + anchors.topMargin: 15 + width: parent.width + Text + { + text: buttonActionContainer.text + anchors.centerIn: parent + } + } +} diff --git a/mix/qml/ScenarioExecution.qml b/mix/qml/ScenarioExecution.qml index 5fcbfab3e..d02e7d3f8 100644 --- a/mix/qml/ScenarioExecution.qml +++ b/mix/qml/ScenarioExecution.qml @@ -9,9 +9,7 @@ import "js/ErrorLocationFormater.js" as ErrorLocationFormater import "." Rectangle { - - border.color: "red" - border.width: 1 + color: "#ededed" Connections { @@ -26,9 +24,10 @@ Rectangle { { anchors.margins: 10 anchors.fill: parent - spacing: 5 + spacing: 10 ScenarioLoader { + height: 70 width: parent.width id: loader } diff --git a/mix/qml/ScenarioLoader.qml b/mix/qml/ScenarioLoader.qml index 0b703c860..b89c1222b 100644 --- a/mix/qml/ScenarioLoader.qml +++ b/mix/qml/ScenarioLoader.qml @@ -37,32 +37,39 @@ RowLayout loaded(state) } } - Button - { + + ScenarioButton { id: restoreScenario - text: qsTr("Restore") + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/restoreIcon@2x.png" onClicked: { restore() } - + text: qsTr("Restore") function restore() { var state = projectModel.stateListModel.reloadStateFromFromProject(scenarioList.currentIndex) restored(state) loaded(state) } - } - Button - { + + ScenarioButton { id: saveScenario text: qsTr("Save") onClicked: { projectModel.saveProjectFile() saved(state) } + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/saveIcon@2x.png" } - Button + + ScenarioButton { id: duplicateScenario text: qsTr("Duplicate") @@ -73,5 +80,9 @@ RowLayout projectModel.stateListModel.save() duplicated(state) } + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/duplicateIcon@2x.png" } } diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index d08ed668d..44873e8db 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -16,7 +16,9 @@ Item { property string defaultAccount: "cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074" //support for old project function fromPlainStateItem(s) { - if (!s.accounts) + console.log("èèèèèèèèèèèè"); + console.log(s); + if (!s.accounts) s.accounts = [stateListModel.newAccount("1000000", QEther.Ether, defaultAccount)]; //support for old project if (!s.contracts) s.contracts = []; @@ -137,7 +139,6 @@ Item { } function toPlainTransactionItem(t) { - console.log(JSON.stringify(t)); var r = { type: t.type, contractId: t.contractId, diff --git a/mix/qml/img/duplicateIcon.png b/mix/qml/img/duplicateIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..b3a2554208e3c2a942a9bfa9484a422c6d8a138e GIT binary patch literal 1020 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 KMNUMnLSTZ1M@~2Z literal 0 HcmV?d00001 diff --git a/mix/qml/img/recycle-discard.png b/mix/qml/img/recycle-discard.png new file mode 100644 index 0000000000000000000000000000000000000000..af1d0959435e93e4d5f55ae572e5b60c42b567c9 GIT binary patch literal 723 zcmV;^0xbQBP)Px%jY&j7R7ef&RZU1#Q562pozX@o9j9p=eUG3BgCK|*TSP);KMTR4l`W#6jV_{v z?IRbtX&KU{bwO>aMKV&PP+6jlLl8j(wdt8DL>fdh&OM#03_J#3^Lz^-mVVsQ0*K7OO1pK{WK|8|Wp7b+qhSiY%A>8vU}h1I zwU9L)CYqQ+^A0b+NC963QUNI>WI;AW`s5ac4OZnbv#Te%fPZ` zK1zhBA{rW`rer&>WG4YJRUd&eFbzAQlsYLV|H548>csqqw015r_$Dz<^da6`x^x|yUsncluhVeuG4n%3xRHmw&ut4N=dja~los>Ky5%FlT3x+C zYf5~U=E#2XFCU*7sPC1OhM{THE7&ZojF3H_Mryag9LDzrd78Hg+&hj`)XOjIWpL|d zm)fkg!quF%9BDqX=3)u-UasX`NYMx}pNF)=dJ2uq!TKTanAFTEnHPUzp=kU!8ooC0 z5zgHXSlx=LABy7Zfk;Z6?~vA?!KxjSqBXscicpd+^jo^)q}Hn={Xk(O@}N4Bo)D6E z*kFFYLfg#UF0{sL+Cw$WlO6TAQb002ovPDHLk FV1gLqOIZK_ literal 0 HcmV?d00001 diff --git a/mix/qml/img/recycle-discard@2x.png b/mix/qml/img/recycle-discard@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c51c21d21199ede62c15ebb50e7635af58e1bfbe GIT binary patch literal 1568 zcmV+*2H*LKP)Px)+DSw~RA>e5S!-+*RTTct?6#Dp@~A+|u0gCyM1^z#K|~TUL@>oC0SQqO!!MMm zA%sXm(D+BA(I_MkA^L~J00}XuXh?iSssuyZ-4K5eQ3wHd1vP?DD5X2c?@pO^y4`Mf zw^J%QO=s`xoO93l=G=47y#oY)0RjO60RjO60RjO60RjO60RjO60RjO6*9L(mjGLCQ zqB|QAjpUm#ftm?PiGKP6VmIca>(7|gALdec6Bu*5CGv$pmV^Xf9>DObTyh#wJsA=@ z0Fi~|g3tG%dRQ*H{`OsS0Dy44h>S6cvz#?lDjN=>>L#xt^pH6r3GWxdIEN0HG8)!Y zFO6Sy@k>xKauSF>PvbTcfsPlTda_;d&~&7ZaO^Pxvjc((BU2UUY_%VmhIB(Qa}-KD zC;%Acl87y#k=yx{o3^U{DXLpkWE}wrb@U-^>y-u5aOSXS55(V~0bq=2Ms%Jf_?Vth znQa{3{LwaTpFb0)k7tkh*&b8?j3H)62#M?`2wgjZ>hTuM+&dem&-iIbcH)#1|DNe_Eta zk~bl?&=TE7nWB(Q361_3N9z0HCH3U!p=3{z!h1}VR+SC3@nkM8wWT>%e_wqH{hBlh zL&rR!jGpyT0wYKE#aGC7BVFPz*FMIHpS!Sz+`075yrzB zwl!ORDQ({Ya1;b)QOVKS3MpEhx0u~uNP7lSC%Jr9xU>vji@A$DEnd3LN9p7i>dnx0Dba_&dF8ZoeQ*gwu`LrR(K{e$A*chnVpOEing!it9RrxIati( z%kjEgwE6n{1ps=tJ6S6(m$c>&p}Ll5fE{5ge2{?N4_IZcOmBG)P9I}C>GTPPFg+;g z+kvl{AhWc;8C1p^rOHu0neKaL3DD*!*~d=gY5+0MMcx9x z^b^v1Z$oSqx6bv<@J4mxEx4gOd2_V1U~&(kuO49AZL3AfA7or|K72Uy@Jw(OWpk@j z#xFw7eZLtaGUsa%9WItmB1F6jEB<{D&|MeomX*$2CHxdWV;_?^TcI^><( zK(+#}a@pQVt!r7H=RLqsRFyM63}IK~XQWRtMr6D^=7WifzC|w@Z~A#rW`ZlP)Z^~S(6nb;i-?;+*0D%C30D%C30D%C30D=D<0{;O2V5305 SQ6=#J0000Px%b4f%&R7ef&mCb7tK^VrHY!bTEARbz%he$qbz$isL8bmSVON+(7!GlPVib%ne zs0S51cn}1^yP~Lw`7)A#ARpHZZ`f#Tqw(~-EDi)3=A{#=AGwx z-e+bfBO}8$bl`t?z_VEca=BdEDVNJj43CJ<(y#&33`V+WGSYS82ESLgsK}+DvF(I}*S}`^xz)&{ydiA~ZA5+O;gpIyq-?;o91`)!dN)Hc9|q zrnjhWFBZSD0yAO={(;b|th3^!G~!mHuyfr8NFMS8#3yUD+DA5s{@2!OwQh$(p)({2 z7brGdm#8ds1A|bUJ-VWcU?5pj*a>j-Xf&J6cd=OP8zAF=jsY4FM2w4E zH1Y1AW<4cH#7IBLbed5iXTDOY*#1kpeuxB#RpSUw;M7eVIdAnyS?$^KSR#=Ka0e!~ f9C!%$Pdo4n78mV*6YJYD00000NkvXXu0mjf;|oPn literal 0 HcmV?d00001 diff --git a/mix/qml/img/recycle-icon@2x.png b/mix/qml/img/recycle-icon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..75b590b2adb7698c418a65899f13189bf8b3fa92 GIT binary patch literal 1435 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 literal 0 HcmV?d00001 diff --git a/mix/qml/img/restoreIcon@2x.png b/mix/qml/img/restoreIcon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..3160b0bf348f7a9b2136ffa84c8eb11f19afbac2 GIT binary patch literal 2447 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 N002ovPDHLkV1ho6ksSa4 literal 0 HcmV?d00001 diff --git a/mix/qml/img/saveIcon.png b/mix/qml/img/saveIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..46e17522b27729f5d8ad767813183ce12f2bfe03 GIT binary patch literal 1068 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 literal 0 HcmV?d00001 diff --git a/mix/res.qrc b/mix/res.qrc index ac0af57ac..e84f77d84 100644 --- a/mix/res.qrc +++ b/mix/res.qrc @@ -68,5 +68,17 @@ qml/img/warningicon.png qml/img/warningicon@2x.png qml/QAddressView.qml + qml/img/recycle-discard.png + qml/img/recycle-discard@2x.png + qml/img/recycle-icon.png + qml/img/recycle-icon@2x.png + qml/img/recycle-keep.png + qml/img/recycle-keep@2x.png + qml/img/restoreIcon.png + qml/img/restoreIcon@2x.png + qml/img/saveIcon.png + qml/img/saveIcon@2x.png + qml/img/duplicateIcon.png + qml/img/duplicateIcon@2x.png From 885494fe2feaaed50c55352d249492344146dfc1 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 8 Jun 2015 15:17:34 +0200 Subject: [PATCH 04/40] Display Catched Events --- mix/ClientModel.cpp | 6 + mix/qml/Block.qml | 240 ++++++++++++++++++++++++++----------- mix/qml/BlockChain.qml | 5 +- mix/qml/StateListModel.qml | 2 - 4 files changed, 176 insertions(+), 77 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 156a5285f..195f49f67 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -759,6 +759,12 @@ void ClientModel::onNewTransaction() { QVariantMap l; l.insert("address", QString::fromStdString(log.address.hex())); + std::ostringstream s; + s << log.data; + l.insert("data", QString::fromStdString(s.str())); + std::ostringstream streamTopic; + streamTopic << log.topics; + l.insert("topic", QString::fromStdString(streamTopic.str())); auto const& sign = log.topics.front(); // first hash supposed to be the event signature. To check auto dataIterator = log.data.begin(); int topicDataIndex = 1; diff --git a/mix/qml/Block.qml b/mix/qml/Block.qml index d3775ea5c..b3865ac4a 100644 --- a/mix/qml/Block.qml +++ b/mix/qml/Block.qml @@ -18,6 +18,28 @@ ColumnLayout property int horizontalMargin: 10 property int trHeight: 30 spacing: 0 + property int openedTr: 0 + + function calculateHeight() + { + if (transactions) + { + if (index >= 0) + return 30 + 30 * transactions.count + openedTr + else + return 30 + } + else + return 30 + } + + onOpenedTrChanged: + { + Layout.preferredHeight = calculateHeight() + height = calculateHeight() + } + + RowLayout { @@ -54,13 +76,43 @@ ColumnLayout RowLayout { + id: rowTransaction Layout.preferredHeight: trHeight + function displayContent() + { + logsText.text = "" + if (index >= 0 && transactions.get(index).logs && transactions.get(index).logs.count) + { + for (var k = 0; k < transactions.get(index).logs.count; k++) + { + var log = transactions.get(index).logs.get(k) + if (log.name) + logsText.text += log.name + ":\n" + else + logsText.text += "log:\n" + + if (log.param) + for (var i = 0; i < log.param.count; i++) + { + var p = log.param.get(i) + logsText.text += p.name + " = " + p.value + " - indexed:" + p.indexed + "\n" + } + else{ + logsText.text += "From : " + log.address + "\n" + } + } + logsText.text += "\n\n" + } + rowDetailedContent.visible = !rowDetailedContent.visible + } + Rectangle { id: trSaveStatus Layout.preferredWidth: statusWidth Layout.preferredHeight: trHeight color: "transparent" + anchors.top: parent.top property bool saveStatus Image { @@ -104,98 +156,144 @@ ColumnLayout Layout.preferredWidth: blockWidth Layout.preferredHeight: parent.height color: "#DEDCDC" - RowLayout + id: rowContentTr + anchors.top: parent.top + ColumnLayout { - anchors.verticalCenter: parent.verticalCenter - spacing: cellSpacing - Text + anchors.top: parent.top + spacing: 10 + RowLayout { - id: hash - anchors.left: parent.left - anchors.leftMargin: horizontalMargin - Layout.preferredWidth: fromWidth - elide: Text.ElideRight - maximumLineCount: 1 - text: { - if (index >= 0) - return transactions.get(index).sender - else - return "" + anchors.top: parent.top + anchors.verticalCenter: parent.verticalCenter + spacing: cellSpacing + Text + { + id: hash + anchors.left: parent.left + anchors.leftMargin: horizontalMargin + Layout.preferredWidth: fromWidth + elide: Text.ElideRight + maximumLineCount: 1 + text: { + if (index >= 0) + return transactions.get(index).sender + else + return "" + } } - } - Text - { - id: func - text: { - if (index >= 0) - parent.userFrienldyToken(transactions.get(index).label) - else - return "" + Text + { + id: func + text: { + if (index >= 0) + parent.userFrienldyToken(transactions.get(index).label) + else + return "" + } + elide: Text.ElideRight + maximumLineCount: 1 + Layout.preferredWidth: toWidth } - elide: Text.ElideRight - maximumLineCount: 1 - Layout.preferredWidth: toWidth - } - function userFrienldyToken(value) - { - if (value && value.indexOf("<") === 0) - return value.split(" - ")[0].replace("<", "") + "." + value.split("> ")[1] + "()"; - else - return value - } - - Text - { - id: returnValue - elide: Text.ElideRight - maximumLineCount: 1 - Layout.preferredWidth: valueWidth - text: { - if (index >= 0 && transactions.get(index).returned) - return transactions.get(index).returned + function userFrienldyToken(value) + { + if (value && value.indexOf("<") === 0) + return value.split(" - ")[0].replace("<", "") + "." + value.split("> ")[1] + "()"; else - return "" + return value } - } - Rectangle - { - Layout.preferredWidth: logsWidth - Layout.preferredHeight: trHeight - 10 - width: logsWidth - color: "transparent" Text { - id: logs - anchors.left: parent.left - anchors.leftMargin: 10 + id: returnValue + elide: Text.ElideRight + maximumLineCount: 1 + Layout.preferredWidth: valueWidth text: { - if (index >= 0 && transactions.get(index).logs && transactions.get(index).logs.count) - { - for (var k = 0; k < transactions.get(index).logs.count; k++) + if (index >= 0 && transactions.get(index).returned) + return transactions.get(index).returned + else + return "" + } + } + + Rectangle + { + Layout.preferredWidth: logsWidth + Layout.preferredHeight: trHeight - 10 + width: logsWidth + color: "transparent" + Text + { + id: logs + anchors.left: parent.left + anchors.leftMargin: 10 + text: { + if (index >= 0 && transactions.get(index).logs && transactions.get(index).logs.count) { - /*console.log("_________________________") - console.log(JSON.stringify(transactions.get(index).logs[k])) - console.log("_________________________")*/ + for (var k = 0; k < transactions.get(index).logs.count; k++) + { + console.log("_________________________") + console.log(JSON.stringify(transactions.get(index).logs[k])) + console.log("_________________________") + } + return transactions.get(index).logs.count } - return transactions.get(index).logs.count + else + return "" } - else - return "" + } + MouseArea { + anchors.fill: parent + onClicked: { + rowTransaction.displayContent(); + } + } + } + + Button + { + id: debug + Layout.preferredWidth: debugActionWidth + text: "debug" + onClicked: + { + clientModel.debugRecord(transactions.get(index).recordIndex); } } } - Button + RowLayout { - id: debug - Layout.preferredWidth: debugActionWidth - text: "debug" - onClicked: + id: rowDetailedContent + visible: false + Layout.preferredHeight:{ + if (index >= 0 && transactions.get(index).logs) + return 100 * transactions.get(index).logs.count + else + return 100 + } + onVisibleChanged: { - clientModel.debugRecord(transactions.get(index).recordIndex); + var lognb = transactions.get(index).logs.count + if (visible) + { + rowContentTr.Layout.preferredHeight = trHeight + 100 * lognb + openedTr += 100 * lognb + } + else + { + rowContentTr.Layout.preferredHeight = trHeight + openedTr -= 100 * lognb + } + } + + Text { + anchors.left: parent.left + anchors.leftMargin: horizontalMargin + id: logsText } } } diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml index 2fc78b0b1..e9b1fc1db 100644 --- a/mix/qml/BlockChain.qml +++ b/mix/qml/BlockChain.qml @@ -127,10 +127,7 @@ ColumnLayout { Layout.preferredWidth: blockChainScrollView.width Layout.preferredHeight: { - if (index >= 0) - return 30 + 30 * blockModel.get(index).transactions.count - else - return 50 + return calculateHeight() } transactions: diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index 44873e8db..dac3e0831 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -16,8 +16,6 @@ Item { property string defaultAccount: "cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074" //support for old project function fromPlainStateItem(s) { - console.log("èèèèèèèèèèèè"); - console.log(s); if (!s.accounts) s.accounts = [stateListModel.newAccount("1000000", QEther.Ether, defaultAccount)]; //support for old project if (!s.contracts) From e2f83a88407b86b6224d71cb3bb1dba868fed296 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 8 Jun 2015 16:39:48 +0200 Subject: [PATCH 05/40] add Timer to avoid FutureTime --- mix/qml/Block.qml | 8 -------- mix/qml/BlockChain.qml | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/mix/qml/Block.qml b/mix/qml/Block.qml index b3865ac4a..0fa69f1bd 100644 --- a/mix/qml/Block.qml +++ b/mix/qml/Block.qml @@ -232,15 +232,7 @@ ColumnLayout anchors.leftMargin: 10 text: { if (index >= 0 && transactions.get(index).logs && transactions.get(index).logs.count) - { - for (var k = 0; k < transactions.get(index).logs.count; k++) - { - console.log("_________________________") - console.log(JSON.stringify(transactions.get(index).logs[k])) - console.log("_________________________") - } return transactions.get(index).logs.count - } else return "" } diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml index e9b1fc1db..202d6d75e 100644 --- a/mix/qml/BlockChain.qml +++ b/mix/qml/BlockChain.qml @@ -260,14 +260,29 @@ ColumnLayout { sourceImg: "qrc:/qml/img/recycle-icon@2x.png" } + Timer + { + id: ensureNotFuturetime + interval: 1000 + repeat: false + running: false + } + ScenarioButton { id: addBlockBtn text: qsTr("Add Block") onClicked: { + if (ensureNotFuturetime.running) + return + if (clientModel.mining || clientModel.running) + return var lastBlock = model.blocks[model.blocks.length - 1] if (lastBlock.status === "pending") + { + ensureNotFuturetime.start() clientModel.mine() + } else addNewBlock() } From 13d99b71c7533436628eb157775fc576deb05a64 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 8 Jun 2015 16:48:54 +0200 Subject: [PATCH 06/40] Avoid future time for Rebuild action --- mix/qml/BlockChain.qml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml index 202d6d75e..4556bd204 100644 --- a/mix/qml/BlockChain.qml +++ b/mix/qml/BlockChain.qml @@ -217,6 +217,8 @@ ColumnLayout { text: qsTr("Rebuild") onClicked: { + if (ensureNotFuturetime.running) + return; for (var j = 0; j < model.blocks.length; j++) { for (var k = 0; k < model.blocks[j].transactions.length; k++) @@ -233,6 +235,7 @@ ColumnLayout { } } } + ensureNotFuturetime.start() clientModel.setupScenario(model); } From bce5486554a8fd5be83f76f3c93b2651df646778 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 9 Jun 2015 08:51:33 +0200 Subject: [PATCH 07/40] misc changes --- mix/ClientModel.cpp | 51 +++++++++++----------- mix/ClientModel.h | 2 +- mix/qml/BlockChain.qml | 54 +++++++++++++++++------ mix/qml/ScenarioButton.qml | 9 ++-- mix/qml/ScenarioLoader.qml | 88 ++++++++++++++++++++------------------ 5 files changed, 119 insertions(+), 85 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 195f49f67..bdb8a0d55 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -211,6 +211,7 @@ QVariantList ClientModel::gasCosts() const void ClientModel::setupScenario(QVariantMap _scenario) { + WriteGuard(x_queueTransactions); m_queueTransactions.clear(); m_running = true; @@ -220,7 +221,6 @@ void ClientModel::setupScenario(QVariantMap _scenario) m_accounts.clear(); std::vector userAccounts; - for (auto const& b: stateAccounts) { QVariantMap account = b.toMap(); @@ -239,23 +239,29 @@ void ClientModel::setupScenario(QVariantMap _scenario) m_accounts[address] = Account(qvariant_cast(account.value("balance"))->toU256Wei(), Account::NormalCreation); } m_ethAccounts->setAccounts(userAccounts); + + bool trToExecute = false; for (auto const& b: blocks) { QVariantList transactions = b.toMap().value("transactions").toList(); m_queueTransactions.push_back(transactions); + trToExecute = transactions.size() > 0; } - m_client->resetState(m_accounts, Secret(m_currentScenario.value("miner").toMap().value("secret").toString().toStdString())); - - connect(this, &ClientModel::newBlock, this, &ClientModel::processNextBlock, Qt::QueuedConnection); - connect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution, Qt::QueuedConnection); - connect(this, &ClientModel::runStateChanged, this, &ClientModel::finalizeBlock, Qt::QueuedConnection); - processNextBlock(); + if (m_queueTransactions.count() > 0 && trToExecute) + { + connect(this, &ClientModel::newBlock, this, &ClientModel::processNextTransactions, Qt::QueuedConnection); + connect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution, Qt::QueuedConnection); + connect(this, &ClientModel::runStateChanged, this, &ClientModel::finalizeBlock, Qt::QueuedConnection); + processNextTransactions(); + } + else + m_running = false; } void ClientModel::stopExecution() { - disconnect(this, &ClientModel::newBlock, this, &ClientModel::processNextBlock); + disconnect(this, &ClientModel::newBlock, this, &ClientModel::processNextTransactions); disconnect(this, &ClientModel::runStateChanged, this, &ClientModel::finalizeBlock); disconnect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution); m_running = false; @@ -263,26 +269,19 @@ void ClientModel::stopExecution() void ClientModel::finalizeBlock() { + m_queueTransactions.pop_front();// pop last execution group. The last block is never mined (pending block) if (m_queueTransactions.size() > 0) mine(); else { - disconnect(this, &ClientModel::newBlock, this, &ClientModel::processNextBlock); - disconnect(this, &ClientModel::runStateChanged, this, &ClientModel::finalizeBlock); - disconnect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution); - m_running = false; + stopExecution(); emit runComplete(); } } - -void ClientModel::processNextBlock() -{ - processNextTransactions(); -} - void ClientModel::processNextTransactions() { + WriteGuard(x_queueTransactions); vector transactionSequence; for (auto const& t: m_queueTransactions.front()) { @@ -311,7 +310,6 @@ void ClientModel::processNextTransactions() transactionSequence.push_back(transactionSettings); } - m_queueTransactions.pop_front(); executeSequence(transactionSequence); } @@ -322,18 +320,13 @@ void ClientModel::executeSequence(vector const& _sequence) qWarning() << "Waiting for current execution to complete"; m_runFuture.waitForFinished(); } - emit runStarted(); - //emit runStateChanged(); - - //run sequence m_runFuture = QtConcurrent::run([=]() { try { vector
deployedContracts; - //onStateReset(); m_gasCosts.clear(); for (TransactionSettings const& transaction: _sequence) { @@ -397,8 +390,8 @@ void ClientModel::executeSequence(vector const& _sequence) } m_gasCosts.append(m_client->lastExecution().gasUsed); onNewTransaction(); - emit runComplete(); } + emit runComplete(); } catch(boost::exception const&) { @@ -416,10 +409,16 @@ void ClientModel::executeSequence(vector const& _sequence) void ClientModel::executeTr(QVariantMap _tr) { + WriteGuard(x_queueTransactions); QVariantList trs; trs.push_back(_tr); m_queueTransactions.push_back(trs); - processNextTransactions(); + if (!m_running) + { + m_running = true; + connect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution, Qt::QueuedConnection); + processNextTransactions(); + } } diff --git a/mix/ClientModel.h b/mix/ClientModel.h index 7cc7b03f6..ed178cfe4 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -256,7 +256,6 @@ private: std::pair resolvePair(QString const& _contractId); QVariant formatStorageValue(SolidityType const& _type, std::unordered_map const& _storage, unsigned _offset, dev::u256 const& _slot); void processNextTransactions(); - void processNextBlock(); void finalizeBlock(); void stopExecution(); @@ -276,6 +275,7 @@ private: CodeModel* m_codeModel = nullptr; QList m_queueTransactions; QVariantMap m_currentScenario; + mutable boost::shared_mutex x_queueTransactions; }; } diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml index 4556bd204..b73d9acbb 100644 --- a/mix/qml/BlockChain.qml +++ b/mix/qml/BlockChain.qml @@ -104,7 +104,6 @@ ColumnLayout { { Layout.preferredHeight: 500 Layout.preferredWidth: parent.width - //height: 500 border.color: "#cccccc" border.width: 2 color: "white" @@ -209,9 +208,10 @@ ColumnLayout { Layout.preferredWidth: parent.width RowLayout { - width: parent.width + width: 4 * 100 anchors.top: parent.top anchors.topMargin: 10 + spacing: 0 ScenarioButton { id: rebuild text: qsTr("Rebuild") @@ -219,22 +219,40 @@ ColumnLayout { { if (ensureNotFuturetime.running) return; + var retBlocks = []; for (var j = 0; j < model.blocks.length; j++) { + var b = model.blocks[j]; + var block = { + hash: b.hash, + number: b.number, + transactions: [], + status: b.status + } for (var k = 0; k < model.blocks[j].transactions.length; k++) { - if (!blockModel.get(j).transactions.get(k).saveStatus) + if (blockModel.get(j).transactions.get(k).saveStatus) { - model.blocks[j].transactions.splice(k, 1) - blockModel.removeTransaction(j, k) - if (model.blocks[j].transactions.length === 0) - { - model.blocks.splice(j, 1); - blockModel.removeBlock(j); - } + block.transactions.push(model.blocks[j].transactions[k]); } } + if (block.transactions.length > 0) + { + retBlocks.push(block) + } + } + if (retBlocks.length === 0) + { + retBlocks.push(projectModel.stateListModel.createEmptyBlock()) + } + + model.blocks = retBlocks + blockModel.clear() + for (var j = 0; j < model.blocks.length; j++) + { + blockModel.append(model.blocks[j]) } + ensureNotFuturetime.start() clientModel.setupScenario(model); } @@ -280,14 +298,21 @@ ColumnLayout { return if (clientModel.mining || clientModel.running) return - var lastBlock = model.blocks[model.blocks.length - 1] - if (lastBlock.status === "pending") + console.log("lllll"); + if (model.blocks.length > 0) { - ensureNotFuturetime.start() - clientModel.mine() + var lastBlock = model.blocks[model.blocks.length - 1] + if (lastBlock.status === "pending") + { + ensureNotFuturetime.start() + clientModel.mine() + } + else + addNewBlock() } else addNewBlock() + } function addNewBlock() @@ -355,6 +380,7 @@ ColumnLayout { itemTr.isFunctionCall = itemTr.functionId !== "" itemTr.returned = _r.returned itemTr.value = QEtherHelper.createEther(_r.value, QEther.Wei) + console.log("sender " + _r.sender) itemTr.sender = _r.sender itemTr.recordIndex = _r.recordIndex itemTr.logs = _r.logs diff --git a/mix/qml/ScenarioButton.qml b/mix/qml/ScenarioButton.qml index e8884cc2e..a2ccf3f78 100644 --- a/mix/qml/ScenarioButton.qml +++ b/mix/qml/ScenarioButton.qml @@ -19,9 +19,12 @@ Rectangle { Image { id: debugImage anchors { - centerIn: parent - bottomMargin: debugImg.pressed ? 0 : 1; - topMargin: debugImg.pressed ? 1 : 0; + left: parent.left + right: parent.right + top: parent.top + bottom: parent.bottom + bottomMargin: debugImg.pressed ? 0 : 2; + topMargin: debugImg.pressed ? 2 : 0; } source: sourceImg fillMode: Image.PreserveAspectFit diff --git a/mix/qml/ScenarioLoader.qml b/mix/qml/ScenarioLoader.qml index b89c1222b..366813a7a 100644 --- a/mix/qml/ScenarioLoader.qml +++ b/mix/qml/ScenarioLoader.qml @@ -14,7 +14,7 @@ RowLayout signal saved(variant scenario) signal duplicated(variant scenario) signal loaded(variant scenario) - + spacing: 0 function init() { scenarioList.load() @@ -38,51 +38,57 @@ RowLayout } } - ScenarioButton { - id: restoreScenario - Layout.preferredWidth: 100 + Row + { + Layout.preferredWidth: 100 * 3 Layout.preferredHeight: 30 - buttonShortcut: "" - sourceImg: "qrc:/qml/img/restoreIcon@2x.png" - onClicked: { - restore() - } - text: qsTr("Restore") - function restore() - { - var state = projectModel.stateListModel.reloadStateFromFromProject(scenarioList.currentIndex) - restored(state) - loaded(state) + spacing: 0 + ScenarioButton { + id: restoreScenario + width: 100 + height: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/restoreIcon@2x.png" + onClicked: { + restore() + } + text: qsTr("Restore") + function restore() + { + var state = projectModel.stateListModel.reloadStateFromFromProject(scenarioList.currentIndex) + restored(state) + loaded(state) + } } - } - ScenarioButton { - id: saveScenario - text: qsTr("Save") - onClicked: { - projectModel.saveProjectFile() - saved(state) + ScenarioButton { + id: saveScenario + text: qsTr("Save") + onClicked: { + projectModel.saveProjectFile() + saved(state) + } + width: 100 + height: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/saveIcon@2x.png" } - Layout.preferredWidth: 100 - Layout.preferredHeight: 30 - buttonShortcut: "" - sourceImg: "qrc:/qml/img/saveIcon@2x.png" - } - ScenarioButton - { - id: duplicateScenario - text: qsTr("Duplicate") - onClicked: { - var state = JSON.parse(JSON.stringify(projectModel.stateListModel.getState(scenarioList.currentIndex))) - state.title = qsTr("Copy of ") + state.title; - projectModel.stateListModel.appendState(state) - projectModel.stateListModel.save() - duplicated(state) + ScenarioButton + { + id: duplicateScenario + text: qsTr("Duplicate") + onClicked: { + var state = JSON.parse(JSON.stringify(projectModel.stateListModel.getState(scenarioList.currentIndex))) + state.title = qsTr("Copy of ") + state.title; + projectModel.stateListModel.appendState(state) + projectModel.stateListModel.save() + duplicated(state) + } + width: 100 + height: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/duplicateIcon@2x.png" } - Layout.preferredWidth: 100 - Layout.preferredHeight: 30 - buttonShortcut: "" - sourceImg: "qrc:/qml/img/duplicateIcon@2x.png" } } From 950cded071128990dd022bfe22415525bd7826e3 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 9 Jun 2015 11:28:23 +0200 Subject: [PATCH 08/40] - add new icons - display tr name in debug Panel --- mix/MixClient.cpp | 1 - mix/qml/Block.qml | 33 ++++++--- mix/qml/BlockChain.qml | 16 ++--- mix/qml/Debugger.qml | 108 +++++++++++++++++------------ mix/qml/MainContent.qml | 4 ++ mix/qml/ScenarioExecution.qml | 1 + mix/qml/ScenarioLoader.qml | 11 ++- mix/qml/StateListModel.qml | 12 +++- mix/qml/img/duplicateIcon.png | Bin 1020 -> 0 bytes mix/qml/img/duplicateIcon@2x.png | Bin 2326 -> 0 bytes mix/qml/img/recycle-discard.png | Bin 723 -> 0 bytes mix/qml/img/recycle-discard@2x.png | Bin 1568 -> 0 bytes mix/qml/img/recycle-icon.png | Bin 697 -> 0 bytes mix/qml/img/recycle-icon@2x.png | Bin 1435 -> 0 bytes mix/qml/img/recycle-keep.png | Bin 904 -> 0 bytes mix/qml/img/recycle-keep@2x.png | Bin 2141 -> 0 bytes mix/qml/img/restoreIcon.png | Bin 1124 -> 0 bytes mix/qml/img/restoreIcon@2x.png | Bin 2447 -> 0 bytes mix/qml/img/saveIcon.png | Bin 1068 -> 0 bytes mix/qml/img/saveIcon@2x.png | Bin 2359 -> 0 bytes mix/res.qrc | 34 +++++---- 21 files changed, 137 insertions(+), 83 deletions(-) delete mode 100644 mix/qml/img/duplicateIcon.png delete mode 100644 mix/qml/img/duplicateIcon@2x.png delete mode 100644 mix/qml/img/recycle-discard.png delete mode 100644 mix/qml/img/recycle-discard@2x.png delete mode 100644 mix/qml/img/recycle-icon.png delete mode 100644 mix/qml/img/recycle-icon@2x.png delete mode 100644 mix/qml/img/recycle-keep.png delete mode 100644 mix/qml/img/recycle-keep@2x.png delete mode 100644 mix/qml/img/restoreIcon.png delete mode 100644 mix/qml/img/restoreIcon@2x.png delete mode 100644 mix/qml/img/saveIcon.png delete mode 100644 mix/qml/img/saveIcon@2x.png diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index f4b0c63a1..90b44b0e7 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -131,7 +131,6 @@ Transaction MixClient::replaceGas(Transaction const& _t, u256 const& _gas, Secre void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _call, bool _gasAuto, Secret const& _secret) { -<<<<<<< HEAD Transaction t = _gasAuto ? replaceGas(_t, m_state.gasLimitRemaining()) : _t; // do debugging run first LastHashes lastHashes(256); diff --git a/mix/qml/Block.qml b/mix/qml/Block.qml index 0fa69f1bd..ba587e4a1 100644 --- a/mix/qml/Block.qml +++ b/mix/qml/Block.qml @@ -19,6 +19,7 @@ ColumnLayout property int trHeight: 30 spacing: 0 property int openedTr: 0 + property int blockIndex function calculateHeight() { @@ -117,7 +118,7 @@ ColumnLayout Image { id: saveStatusImage - source: "qrc:/qml/img/recycle-discard@2x.png" + source: "qrc:/qml/img/recyclediscard@2x.png" width: statusWidth fillMode: Image.PreserveAspectFit anchors.verticalCenter: parent.verticalCenter @@ -133,9 +134,9 @@ ColumnLayout onSaveStatusChanged: { if (saveStatus) - saveStatusImage.source = "qrc:/qml/img/recycle-keep@2x.png" + saveStatusImage.source = "qrc:/qml/img/recyclekeep@2x.png" else - saveStatusImage.source = "qrc:/qml/img/recycle-discard@2x.png" + saveStatusImage.source = "qrc:/qml/img/recyclediscard@2x.png" if (index >= 0) transactions.get(index).saveStatus = saveStatus @@ -245,14 +246,30 @@ ColumnLayout } } - Button + Rectangle { - id: debug Layout.preferredWidth: debugActionWidth - text: "debug" - onClicked: + Layout.preferredHeight: trHeight - 10 + color: "transparent" + Image { + source: "qrc:/qml/img/rightarrow@2x.png" + width: statusWidth + fillMode: Image.PreserveAspectFit + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + visible: transactions.get(index).recordIndex !== undefined + } + MouseArea { - clientModel.debugRecord(transactions.get(index).recordIndex); + anchors.fill: parent + onClicked: + { + if (transactions.get(index).recordIndex) + { + debugTrRequested = [ blockIndex, index ] + clientModel.debugRecord(transactions.get(index).recordIndex); + } + } } } } diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml index b73d9acbb..75073860f 100644 --- a/mix/qml/BlockChain.qml +++ b/mix/qml/BlockChain.qml @@ -16,6 +16,7 @@ ColumnLayout { property variant model spacing: 0 property int previousWidth + property variant debugTrRequested: [] onWidthChanged: { @@ -62,7 +63,7 @@ ColumnLayout { Layout.preferredHeight: 25 Image { id: debugImage - source: "qrc:/qml/img/recycle-icon@2x.png" + source: "qrc:/qml/img/recycleicon@2x.png" Layout.preferredWidth: statusWidth Layout.preferredHeight: 25 fillMode: Image.PreserveAspectFit @@ -95,7 +96,7 @@ ColumnLayout { } Label { - text: "Action" + text: "" Layout.preferredWidth: debugActionWidth } } @@ -128,7 +129,7 @@ ColumnLayout { { return calculateHeight() } - + blockIndex: index transactions: { if (index >= 0) @@ -260,7 +261,7 @@ ColumnLayout { Layout.preferredWidth: 100 Layout.preferredHeight: 30 buttonShortcut: "" - sourceImg: "qrc:/qml/img/recycle-icon@2x.png" + sourceImg: "qrc:/qml/img/recycleicon@2x.png" } ScenarioButton { @@ -278,7 +279,7 @@ ColumnLayout { Layout.preferredWidth: 100 Layout.preferredHeight: 30 buttonShortcut: "" - sourceImg: "qrc:/qml/img/recycle-icon@2x.png" + sourceImg: "qrc:/qml/img/sendtransactionicon@2x.png" } Timer @@ -324,7 +325,7 @@ ColumnLayout { Layout.preferredWidth: 100 Layout.preferredHeight: 30 buttonShortcut: "" - sourceImg: "qrc:/qml/img/recycle-icon@2x.png" + sourceImg: "qrc:/qml/img/addblock@2x.png" } Connections @@ -380,7 +381,6 @@ ColumnLayout { itemTr.isFunctionCall = itemTr.functionId !== "" itemTr.returned = _r.returned itemTr.value = QEtherHelper.createEther(_r.value, QEther.Wei) - console.log("sender " + _r.sender) itemTr.sender = _r.sender itemTr.recordIndex = _r.recordIndex itemTr.logs = _r.logs @@ -401,7 +401,7 @@ ColumnLayout { Layout.preferredWidth: 100 Layout.preferredHeight: 30 buttonShortcut: "" - sourceImg: "qrc:/qml/img/recycle-icon@2x.png" + sourceImg: "qrc:/qml/img/newaccounticon@2x.png" } } } diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index 7827931b0..3a0ed61a4 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -11,7 +11,7 @@ import "." Rectangle { id: debugPanel - property alias debugSlider: statesSlider + property alias debugSlider: statesSlider property alias solLocals: solLocals property alias solStorage: solStorage property alias solCallStack: solCallStack @@ -39,6 +39,11 @@ Rectangle { machineStates.updateHeight(); } + function setTr(tr) + { + trName.text = tr.label + } + function displayCompilationErrorIfAny() { debugScrollArea.visible = false; @@ -104,28 +109,67 @@ Rectangle { property alias solLocalsHeightSettings: solLocalsRect.height } - Splitter { + ColumnLayout { id: debugScrollArea anchors.fill: parent - orientation: Qt.Vertical + //orientation: Qt.Vertical + spacing: 0 + RowLayout + { + Layout.preferredWidth: parent.width + Layout.preferredHeight: 30 + Rectangle + { + Layout.preferredWidth: parent.width + Layout.preferredHeight: parent.height + color: "transparent" + Text { + anchors.centerIn: parent + text: qsTr("Current Transaction") + } + + Rectangle + { + anchors.left: parent.left + anchors.leftMargin: 10 + width: 30 + height: parent.height + color: "transparent" + anchors.verticalCenter: parent.verticalCenter + Image { + source: "qrc:/qml/img/leftarrow@2x.png" + width: parent.width + fillMode: Image.PreserveAspectFit + anchors.centerIn: parent + } + MouseArea + { + anchors.fill: parent + onClicked: + { + Debugger.init(null); + panelClosed() + } + } + } + } + } - /*TransactionLog { - id: transactionLog - Layout.fillWidth: true - Layout.minimumHeight: 130 - height: 250 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: machineStates.sideMargin - anchors.rightMargin: machineStates.sideMargin - anchors.topMargin: machineStates.sideMargin - }*/ - - Button + RowLayout { - text: qsTr("close") - onClicked: panelClosed() + Layout.preferredWidth: parent.width + Layout.preferredHeight: 30 + Rectangle + { + Layout.preferredWidth: parent.width + Layout.preferredHeight: parent.height + color: "#2C79D3" + Text { + id: trName + color: "white" + anchors.centerIn: parent + } + } } ScrollView @@ -170,32 +214,6 @@ Rectangle { spacing: 3 layoutDirection: Qt.LeftToRight - /*StepActionImage - { - id: playAction - enabledStateImg: "qrc:/qml/img/play_button.png" - disableStateImg: "qrc:/qml/img/play_button.png" - buttonLeft: true - onClicked: projectModel.stateListModel.runState(transactionLog.selectedStateIndex) - width: 23 - buttonShortcut: "Ctrl+Shift+F8" - buttonTooltip: qsTr("Start Debugging") - visible: true - Layout.alignment: Qt.AlignLeft - } - - StepActionImage - { - id: pauseAction - enabledStateImg: "qrc:/qml/img/stop_button2x.png" - disableStateImg: "qrc:/qml/img/stop_button2x.png" - onClicked: Debugger.init(null); - width: 23 - buttonShortcut: "Ctrl+Shift+F9" - buttonTooltip: qsTr("Stop Debugging") - visible: true - }*/ - StepActionImage { id: runBackAction; diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index 4af8ece46..21aed8af1 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -224,6 +224,10 @@ Rectangle { onDebugDataReady: { scenarioExe.visible = false debugPanel.visible = true + if (scenarioExe.bc.debugTrRequested) + { + debugPanel.setTr(scenarioExe.bc.model.blocks[scenarioExe.bc.debugTrRequested[0]].transactions[scenarioExe.bc.debugTrRequested[1]]) + } } } diff --git a/mix/qml/ScenarioExecution.qml b/mix/qml/ScenarioExecution.qml index d02e7d3f8..a5053e4d7 100644 --- a/mix/qml/ScenarioExecution.qml +++ b/mix/qml/ScenarioExecution.qml @@ -10,6 +10,7 @@ import "." Rectangle { color: "#ededed" + property alias bc: blockChain Connections { diff --git a/mix/qml/ScenarioLoader.qml b/mix/qml/ScenarioLoader.qml index 366813a7a..c659eb297 100644 --- a/mix/qml/ScenarioLoader.qml +++ b/mix/qml/ScenarioLoader.qml @@ -48,7 +48,7 @@ RowLayout width: 100 height: 30 buttonShortcut: "" - sourceImg: "qrc:/qml/img/restoreIcon@2x.png" + sourceImg: "qrc:/qml/img/restoreicon@2x.png" onClicked: { restore() } @@ -71,7 +71,7 @@ RowLayout width: 100 height: 30 buttonShortcut: "" - sourceImg: "qrc:/qml/img/saveIcon@2x.png" + sourceImg: "qrc:/qml/img/saveicon@2x.png" } ScenarioButton @@ -79,16 +79,13 @@ RowLayout id: duplicateScenario text: qsTr("Duplicate") onClicked: { - var state = JSON.parse(JSON.stringify(projectModel.stateListModel.getState(scenarioList.currentIndex))) - state.title = qsTr("Copy of ") + state.title; - projectModel.stateListModel.appendState(state) - projectModel.stateListModel.save() + projectModel.stateListModel.duplicateState(scenarioList.currentIndex) duplicated(state) } width: 100 height: 30 buttonShortcut: "" - sourceImg: "qrc:/qml/img/duplicateIcon@2x.png" + sourceImg: "qrc:/qml/img/duplicateicon@2x.png" } } } diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index dac3e0831..cb9688524 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -16,6 +16,7 @@ Item { property string defaultAccount: "cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074" //support for old project function fromPlainStateItem(s) { + console.log("ggg " + s) if (!s.accounts) s.accounts = [stateListModel.newAccount("1000000", QEther.Ether, defaultAccount)]; //support for old project if (!s.contracts) @@ -242,6 +243,15 @@ Item { return { name: name, secret: _secret, balance: QEtherHelper.createEther(_balance, _unit), address: address }; } + function duplicateState(index) + { + var state = stateList[index] + var item = fromPlainStateItem(toPlainStateItem(state)) + item.title = qsTr("Copy of") + " " + state.title + appendState(item) + save() + } + function createEmptyBlock() { return { @@ -380,11 +390,9 @@ Item { function reloadStateFromFromProject(index) { - console.log(JSON.stringify(data)) if (data) { var item = fromPlainStateItem(data.states[index]) - stateListModel.set(index, item) stateList[index] = item return item diff --git a/mix/qml/img/duplicateIcon.png b/mix/qml/img/duplicateIcon.png deleted file mode 100644 index b3a2554208e3c2a942a9bfa9484a422c6d8a138e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1020 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 FV1gLqOIZK_ diff --git a/mix/qml/img/recycle-discard@2x.png b/mix/qml/img/recycle-discard@2x.png deleted file mode 100644 index c51c21d21199ede62c15ebb50e7635af58e1bfbe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1568 zcmV+*2H*LKP)Px)+DSw~RA>e5S!-+*RTTct?6#Dp@~A+|u0gCyM1^z#K|~TUL@>oC0SQqO!!MMm zA%sXm(D+BA(I_MkA^L~J00}XuXh?iSssuyZ-4K5eQ3wHd1vP?DD5X2c?@pO^y4`Mf zw^J%QO=s`xoO93l=G=47y#oY)0RjO60RjO60RjO60RjO60RjO60RjO6*9L(mjGLCQ zqB|QAjpUm#ftm?PiGKP6VmIca>(7|gALdec6Bu*5CGv$pmV^Xf9>DObTyh#wJsA=@ z0Fi~|g3tG%dRQ*H{`OsS0Dy44h>S6cvz#?lDjN=>>L#xt^pH6r3GWxdIEN0HG8)!Y zFO6Sy@k>xKauSF>PvbTcfsPlTda_;d&~&7ZaO^Pxvjc((BU2UUY_%VmhIB(Qa}-KD zC;%Acl87y#k=yx{o3^U{DXLpkWE}wrb@U-^>y-u5aOSXS55(V~0bq=2Ms%Jf_?Vth znQa{3{LwaTpFb0)k7tkh*&b8?j3H)62#M?`2wgjZ>hTuM+&dem&-iIbcH)#1|DNe_Eta zk~bl?&=TE7nWB(Q361_3N9z0HCH3U!p=3{z!h1}VR+SC3@nkM8wWT>%e_wqH{hBlh zL&rR!jGpyT0wYKE#aGC7BVFPz*FMIHpS!Sz+`075yrzB zwl!ORDQ({Ya1;b)QOVKS3MpEhx0u~uNP7lSC%Jr9xU>vji@A$DEnd3LN9p7i>dnx0Dba_&dF8ZoeQ*gwu`LrR(K{e$A*chnVpOEing!it9RrxIati( z%kjEgwE6n{1ps=tJ6S6(m$c>&p}Ll5fE{5ge2{?N4_IZcOmBG)P9I}C>GTPPFg+;g z+kvl{AhWc;8C1p^rOHu0neKaL3DD*!*~d=gY5+0MMcx9x z^b^v1Z$oSqx6bv<@J4mxEx4gOd2_V1U~&(kuO49AZL3AfA7or|K72Uy@Jw(OWpk@j z#xFw7eZLtaGUsa%9WItmB1F6jEB<{D&|MeomX*$2CHxdWV;_?^TcI^><( zK(+#}a@pQVt!r7H=RLqsRFyM63}IK~XQWRtMr6D^=7WifzC|w@Z~A#rW`ZlP)Z^~S(6nb;i-?;+*0D%C30D%C30D%C30D=D<0{;O2V5305 SQ6=#J0000Px%b4f%&R7ef&mCb7tK^VrHY!bTEARbz%he$qbz$isL8bmSVON+(7!GlPVib%ne zs0S51cn}1^yP~Lw`7)A#ARpHZZ`f#Tqw(~-EDi)3=A{#=AGwx z-e+bfBO}8$bl`t?z_VEca=BdEDVNJj43CJ<(y#&33`V+WGSYS82ESLgsK}+DvF(I}*S}`^xz)&{ydiA~ZA5+O;gpIyq-?;o91`)!dN)Hc9|q zrnjhWFBZSD0yAO={(;b|th3^!G~!mHuyfr8NFMS8#3yUD+DA5s{@2!OwQh$(p)({2 z7brGdm#8ds1A|bUJ-VWcU?5pj*a>j-Xf&J6cd=OP8zAF=jsY4FM2w4E zH1Y1AW<4cH#7IBLbed5iXTDOY*#1kpeuxB#RpSUw;M7eVIdAnyS?$^KSR#=Ka0e!~ f9C!%$Pdo4n78mV*6YJYD00000NkvXXu0mjf;|oPn diff --git a/mix/qml/img/recycle-icon@2x.png b/mix/qml/img/recycle-icon@2x.png deleted file mode 100644 index 75b590b2adb7698c418a65899f13189bf8b3fa92..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1435 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 diff --git a/mix/qml/img/restoreIcon@2x.png b/mix/qml/img/restoreIcon@2x.png deleted file mode 100644 index 3160b0bf348f7a9b2136ffa84c8eb11f19afbac2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2447 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 N002ovPDHLkV1ho6ksSa4 diff --git a/mix/qml/img/saveIcon.png b/mix/qml/img/saveIcon.png deleted file mode 100644 index 46e17522b27729f5d8ad767813183ce12f2bfe03..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1068 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 diff --git a/mix/res.qrc b/mix/res.qrc index e84f77d84..b50aa3d9f 100644 --- a/mix/res.qrc +++ b/mix/res.qrc @@ -68,17 +68,27 @@ qml/img/warningicon.png qml/img/warningicon@2x.png qml/QAddressView.qml - qml/img/recycle-discard.png - qml/img/recycle-discard@2x.png - qml/img/recycle-icon.png - qml/img/recycle-icon@2x.png - qml/img/recycle-keep.png - qml/img/recycle-keep@2x.png - qml/img/restoreIcon.png - qml/img/restoreIcon@2x.png - qml/img/saveIcon.png - qml/img/saveIcon@2x.png - qml/img/duplicateIcon.png - qml/img/duplicateIcon@2x.png + qml/img/addblock.png + qml/img/addblock@2x.png + qml/img/duplicateicon.png + qml/img/duplicateicon@2x.png + qml/img/leftarrow.png + qml/img/leftarrow@2x.png + qml/img/newaccounticon.png + qml/img/newaccounticon@2x.png + qml/img/recyclediscard.png + qml/img/recyclediscard@2x.png + qml/img/recycleicon.png + qml/img/recycleicon@2x.png + qml/img/recyclekeep.png + qml/img/recyclekeep@2x.png + qml/img/restoreicon.png + qml/img/restoreicon@2x.png + qml/img/rightarrow.png + qml/img/rightarrow@2x.png + qml/img/saveicon.png + qml/img/saveicon@2x.png + qml/img/sendtransactionicon.png + qml/img/sendtransactionicon@2x.png From 2e639c198a3aa3729377085191587ef354761176 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 9 Jun 2015 21:06:39 +0200 Subject: [PATCH 09/40] misc changes --- mix/ClientModel.cpp | 63 ++++++++++++++++----------- mix/ClientModel.h | 6 ++- mix/qml/Block.qml | 35 ++++++++++++++- mix/qml/BlockChain.qml | 73 +++++++++++++++++++++++-------- mix/qml/MainContent.qml | 2 +- mix/qml/ScenarioButton.qml | 2 + mix/qml/ScenarioLoader.qml | 88 +++++++++++++++++++++++++++++++++++++- 7 files changed, 220 insertions(+), 49 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index bdb8a0d55..c834ca5c7 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -83,14 +83,11 @@ ClientModel::ClientModel(): qRegisterMetaType("QCallData"); qRegisterMetaType("RecordLogEntry*"); - //connect(this, &ClientModel::runComplete, this, &ClientModel::showDebugger, Qt::QueuedConnection); m_client.reset(new MixClient(QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString())); m_ethAccounts = make_shared([=](){return m_client.get();}, std::vector()); m_web3Server.reset(new Web3Server(*m_rpcConnector.get(), m_ethAccounts, std::vector(), m_client.get())); connect(m_web3Server.get(), &Web3Server::newTransaction, this, &ClientModel::onNewTransaction, Qt::DirectConnection); - - } ClientModel::~ClientModel() @@ -211,8 +208,8 @@ QVariantList ClientModel::gasCosts() const void ClientModel::setupScenario(QVariantMap _scenario) { + onStateReset(); WriteGuard(x_queueTransactions); - m_queueTransactions.clear(); m_running = true; m_currentScenario = _scenario; @@ -220,7 +217,7 @@ void ClientModel::setupScenario(QVariantMap _scenario) QVariantList stateAccounts = _scenario.value("accounts").toList(); m_accounts.clear(); - std::vector userAccounts; + m_accountsSecret.clear(); for (auto const& b: stateAccounts) { QVariantMap account = b.toMap(); @@ -228,7 +225,7 @@ void ClientModel::setupScenario(QVariantMap _scenario) if (account.contains("secret")) { KeyPair key(Secret(account.value("secret").toString().toStdString())); - userAccounts.push_back(key); + m_accountsSecret.push_back(key); address = key.address(); } else if (account.contains("address")) @@ -238,7 +235,7 @@ void ClientModel::setupScenario(QVariantMap _scenario) m_accounts[address] = Account(qvariant_cast(account.value("balance"))->toU256Wei(), Account::NormalCreation); } - m_ethAccounts->setAccounts(userAccounts); + m_ethAccounts->setAccounts(m_accountsSecret); bool trToExecute = false; for (auto const& b: blocks) @@ -250,15 +247,20 @@ void ClientModel::setupScenario(QVariantMap _scenario) m_client->resetState(m_accounts, Secret(m_currentScenario.value("miner").toMap().value("secret").toString().toStdString())); if (m_queueTransactions.count() > 0 && trToExecute) { - connect(this, &ClientModel::newBlock, this, &ClientModel::processNextTransactions, Qt::QueuedConnection); - connect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution, Qt::QueuedConnection); - connect(this, &ClientModel::runStateChanged, this, &ClientModel::finalizeBlock, Qt::QueuedConnection); + setupExecutionChain(); processNextTransactions(); } else m_running = false; } +void ClientModel::setupExecutionChain() +{ + connect(this, &ClientModel::newBlock, this, &ClientModel::processNextTransactions, Qt::QueuedConnection); + connect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution, Qt::QueuedConnection); + connect(this, &ClientModel::runStateChanged, this, &ClientModel::finalizeBlock, Qt::QueuedConnection); +} + void ClientModel::stopExecution() { disconnect(this, &ClientModel::newBlock, this, &ClientModel::processNextTransactions); @@ -302,7 +304,8 @@ void ClientModel::processNextTransactions() bool isFunctionCall = transaction.value("isFunctionCall").toBool(); if (contractId.isEmpty() && m_codeModel->hasContract()) //TODO: This is to support old project files, remove later contractId = m_codeModel->contracts().keys()[0]; - TransactionSettings transactionSettings(contractId, functionId, value, gas, gasAuto, gasPrice, Secret(sender.toStdString()), isContractCreation, isFunctionCall); + Secret f = Secret(sender.toStdString()); + TransactionSettings transactionSettings(contractId, functionId, value, gas, gasAuto, gasPrice, f, isContractCreation, isFunctionCall); transactionSettings.parameterValues = transaction.value("parameters").toMap(); if (contractId == functionId || functionId == "Constructor") @@ -326,12 +329,11 @@ void ClientModel::executeSequence(vector const& _sequence) { try { - vector
deployedContracts; m_gasCosts.clear(); for (TransactionSettings const& transaction: _sequence) { std::pair ctrInstance = resolvePair(transaction.contractId); - QString address = resolveToken(ctrInstance, deployedContracts); + QString address = resolveToken(ctrInstance); if (!transaction.isFunctionCall) { callAddress(Address(address.toStdString()), bytes(), transaction); @@ -364,7 +366,7 @@ void ClientModel::executeSequence(vector const& _sequence) if (type->type().type == SolidityType::Type::Address && value.toString().startsWith("<")) { std::pair ctrParamInstance = resolvePair(value.toString()); - value = QVariant(resolveToken(ctrParamInstance, deployedContracts)); + value = QVariant(resolveToken(ctrParamInstance)); } encoder.encode(value, type->type()); } @@ -374,8 +376,7 @@ void ClientModel::executeSequence(vector const& _sequence) bytes param = encoder.encodedData(); contractCode.insert(contractCode.end(), param.begin(), param.end()); Address newAddress = deployContract(contractCode, transaction); - deployedContracts.push_back(newAddress); - std::pair contractToken = retrieveToken(transaction.contractId, deployedContracts); + std::pair contractToken = retrieveToken(transaction.contractId); m_contractAddresses[contractToken] = newAddress; m_contractNames[newAddress] = contractToken.first; contractAddressesChanged(); @@ -416,7 +417,7 @@ void ClientModel::executeTr(QVariantMap _tr) if (!m_running) { m_running = true; - connect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution, Qt::QueuedConnection); + setupExecutionChain(); processNextTransactions(); } } @@ -433,19 +434,19 @@ std::pair ClientModel::resolvePair(QString const& _contractId) return ret; } -QString ClientModel::resolveToken(std::pair const& _value, vector
const& _contracts) +QString ClientModel::resolveToken(std::pair const& _value) { - if (_contracts.size() > 0) - return QString::fromStdString("0x" + dev::toHex(m_contractAddresses[_value].ref())); //dev::toHex(_contracts.at(_value.second).ref())); + if (m_contractAddresses.size() > 0) + return QString::fromStdString("0x" + dev::toHex(m_contractAddresses[_value].ref())); else return _value.first; } -std::pair ClientModel::retrieveToken(QString const& _value, vector
const& _contracts) +std::pair ClientModel::retrieveToken(QString const& _value) { std::pair ret; ret.first = _value; - ret.second = _contracts.size() - 1; + ret.second = m_contractAddresses.size(); return ret; } @@ -679,6 +680,7 @@ void ClientModel::onStateReset() m_contractNames.clear(); m_stdContractAddresses.clear(); m_stdContractNames.clear(); + m_queueTransactions.clear(); emit stateCleared(); } @@ -801,8 +803,21 @@ void ClientModel::onNewTransaction() logs.push_back(l); } } - QString sender = QString::fromStdString(dev::toHex(tr.sender.ref())); - QString label = contract + "." + function + "()"; + + QString sender; + for (auto const& secret: m_accountsSecret) + { + if (secret.address() == tr.sender) + { + sender = QString::fromStdString(dev::toHex(secret.secret().ref())); + break; + } + } + QString label; + if (function != QObject::tr("")) + label = contract + "." + function + "()"; + else + label = contract; RecordLogEntry* log = new RecordLogEntry(recordIndex, transactionIndex, contract, function, value, address, returned, tr.isCall(), RecordLogEntry::RecordType::Transaction, gasUsed, sender, label, inputParameters, logs); QQmlEngine::setObjectOwnership(log, QQmlEngine::JavaScriptOwnership); diff --git a/mix/ClientModel.h b/mix/ClientModel.h index ed178cfe4..c062aa4a7 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -251,13 +251,14 @@ private: void onStateReset(); void showDebuggerForTransaction(ExecutionResult const& _t); QVariant formatValue(SolidityType const& _type, dev::u256 const& _value); - QString resolveToken(std::pair const& _value, std::vector
const& _contracts); - std::pair retrieveToken(QString const& _value, std::vector
const& _contracts); + QString resolveToken(std::pair const& _value); + std::pair retrieveToken(QString const& _value); std::pair resolvePair(QString const& _contractId); QVariant formatStorageValue(SolidityType const& _type, std::unordered_map const& _storage, unsigned _offset, dev::u256 const& _slot); void processNextTransactions(); void finalizeBlock(); void stopExecution(); + void setupExecutionChain(); std::atomic m_running; std::atomic m_mining; @@ -267,6 +268,7 @@ private: std::unique_ptr m_web3Server; std::shared_ptr m_ethAccounts; std::unordered_map m_accounts; + std::vector m_accountsSecret; QList m_gasCosts; std::map, Address> m_contractAddresses; std::map m_contractNames; diff --git a/mix/qml/Block.qml b/mix/qml/Block.qml index ba587e4a1..b56b1f4d0 100644 --- a/mix/qml/Block.qml +++ b/mix/qml/Block.qml @@ -20,6 +20,7 @@ ColumnLayout spacing: 0 property int openedTr: 0 property int blockIndex + property variant scenario function calculateHeight() { @@ -201,7 +202,12 @@ ColumnLayout function userFrienldyToken(value) { if (value && value.indexOf("<") === 0) - return value.split(" - ")[0].replace("<", "") + "." + value.split("> ")[1] + "()"; + { + if (value.split("> ")[1] === " - ") + return value.split(" - ")[0].replace("<", "") + else + return value.split(" - ")[0].replace("<", "") + "." + value.split("> ")[1] + "()"; + } else return value } @@ -251,7 +257,34 @@ ColumnLayout Layout.preferredWidth: debugActionWidth Layout.preferredHeight: trHeight - 10 color: "transparent" + + Image { + source: "qrc:/qml/img/edit.png" + width: 18 + fillMode: Image.PreserveAspectFit + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + } + MouseArea + { + anchors.fill: parent + onClicked: + { + transactionDialog.stateAccounts = scenario.accounts + transactionDialog.execute = false + transactionDialog.open(index, blockIndex, transactions.get(index)) + } + } + } + + Rectangle + { + Layout.preferredWidth: debugActionWidth + Layout.preferredHeight: trHeight - 10 + color: "transparent" + Image { + id: debugImg source: "qrc:/qml/img/rightarrow@2x.png" width: statusWidth fillMode: Image.PreserveAspectFit diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml index 75073860f..5efdf8a60 100644 --- a/mix/qml/BlockChain.qml +++ b/mix/qml/BlockChain.qml @@ -17,6 +17,12 @@ ColumnLayout { spacing: 0 property int previousWidth property variant debugTrRequested: [] + signal chainChanged + + onChainChanged: { + reBuildNeeded.start() + } + onWidthChanged: { @@ -40,6 +46,8 @@ ColumnLayout { { if (!scenario) return; + if (model) + chainChanged() model = scenario blockModel.clear() for (var b in model.blocks) @@ -124,6 +132,7 @@ ColumnLayout { model: blockModel Block { + scenario: blockChainPanel.model Layout.preferredWidth: blockChainScrollView.width Layout.preferredHeight: { @@ -220,6 +229,7 @@ ColumnLayout { { if (ensureNotFuturetime.running) return; + reBuildNeeded.stop() var retBlocks = []; for (var j = 0; j < model.blocks.length; j++) { @@ -233,26 +243,18 @@ ColumnLayout { for (var k = 0; k < model.blocks[j].transactions.length; k++) { if (blockModel.get(j).transactions.get(k).saveStatus) - { block.transactions.push(model.blocks[j].transactions[k]); - } } if (block.transactions.length > 0) - { retBlocks.push(block) - } } if (retBlocks.length === 0) - { retBlocks.push(projectModel.stateListModel.createEmptyBlock()) - } model.blocks = retBlocks blockModel.clear() for (var j = 0; j < model.blocks.length; j++) - { blockModel.append(model.blocks[j]) - } ensureNotFuturetime.start() clientModel.setupScenario(model); @@ -262,6 +264,23 @@ ColumnLayout { Layout.preferredHeight: 30 buttonShortcut: "" sourceImg: "qrc:/qml/img/recycleicon@2x.png" + Timer + { + id: reBuildNeeded + repeat: true + interval: 1000 + running: false + onTriggered: { + if (!parent.fillColor || parent.fillColor === "white") + parent.fillColor = "orange" + else + parent.fillColor = "white" + } + onRunningChanged: { + if (!running) + parent.fillColor = "white" + } + } } ScenarioButton { @@ -274,6 +293,7 @@ ColumnLayout { model.blocks.push(projectModel.stateListModel.createEmptyBlock()); var item = TransactionHelper.defaultTransaction() transactionDialog.stateAccounts = model.accounts + transactionDialog.execute = true transactionDialog.open(model.blocks[model.blocks.length - 1].transactions.length, model.blocks.length - 1, item) } Layout.preferredWidth: 100 @@ -299,7 +319,6 @@ ColumnLayout { return if (clientModel.mining || clientModel.running) return - console.log("lllll"); if (model.blocks.length > 0) { var lastBlock = model.blocks[model.blocks.length - 1] @@ -351,25 +370,30 @@ ColumnLayout { { var blockIndex = parseInt(_r.transactionIndex.split(":")[0]) - 1 var trIndex = parseInt(_r.transactionIndex.split(":")[1]) - if (blockIndex <= model.blocks.length) + console.log("kkkk" + blockIndex) + console.log(trIndex) + if (blockIndex <= model.blocks.length - 1) { var item = model.blocks[blockIndex] - if (trIndex <= item.transactions.length) + if (trIndex <= item.transactions.length - 1) { var tr = item.transactions[trIndex] + console.log(JSON.stringify(_r)) tr.returned = _r.returned tr.recordIndex = _r.recordIndex tr.logs = _r.logs + tr.sender = _r.sender var trModel = blockModel.getTransaction(blockIndex, trIndex) trModel.returned = _r.returned trModel.recordIndex = _r.recordIndex trModel.logs = _r.logs + trModel.sender = _r.sender blockModel.setTransaction(blockIndex, trIndex, trModel) return; } } - // tr is not in the list. coming from JavaScript + // tr is not in the list. var itemTr = TransactionHelper.defaultTransaction() itemTr.saveStatus = false itemTr.functionId = _r.function @@ -397,6 +421,7 @@ ColumnLayout { text: qsTr("New Account") onClicked: { model.accounts.push(projectModel.stateListModel.newAccount("1000000", QEther.Ether)) + chainChanged() } Layout.preferredWidth: 100 Layout.preferredHeight: 30 @@ -408,15 +433,25 @@ ColumnLayout { TransactionDialog { id: transactionDialog + property bool execute onAccepted: { var item = transactionDialog.getItem() - var lastBlock = model.blocks[model.blocks.length - 1]; - if (lastBlock.status === "mined") - model.blocks.push(projectModel.stateListModel.createEmptyBlock()); - model.blocks[model.blocks.length - 1].transactions.push(item) - blockModel.appendTransaction(item) - if (!clientModel.running) - clientModel.executeTr(item) + if (execute) + { + var lastBlock = model.blocks[model.blocks.length - 1]; + if (lastBlock.status === "mined") + model.blocks.push(projectModel.stateListModel.createEmptyBlock()); + model.blocks[model.blocks.length - 1].transactions.push(item) + blockModel.appendTransaction(item) + if (!clientModel.running) + clientModel.executeTr(item) + } + else { + model.blocks[blockIndex].transactions[transactionIndex] = item + blockModel.setTransaction(blockIndex, transactionIndex, item) + chainChanged() + } + } } } diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index 21aed8af1..22aa78f38 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -234,8 +234,8 @@ Rectangle { Connections { target: debugPanel onPanelClosed: { - scenarioExe.visible = true debugPanel.visible = false + scenarioExe.visible = true } } } diff --git a/mix/qml/ScenarioButton.qml b/mix/qml/ScenarioButton.qml index a2ccf3f78..dbe6dd13a 100644 --- a/mix/qml/ScenarioButton.qml +++ b/mix/qml/ScenarioButton.qml @@ -8,6 +8,7 @@ Rectangle { property string text property string buttonShortcut property string sourceImg + property string fillColor signal clicked Rectangle { @@ -16,6 +17,7 @@ Rectangle { border.color: "#cccccc" border.width: 1 radius: 4 + color: parent.fillColor ? parent.fillColor : "white" Image { id: debugImage anchors { diff --git a/mix/qml/ScenarioLoader.qml b/mix/qml/ScenarioLoader.qml index c659eb297..50e958a5c 100644 --- a/mix/qml/ScenarioLoader.qml +++ b/mix/qml/ScenarioLoader.qml @@ -1,8 +1,10 @@ import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Controls.Styles 1.1 -import QtQuick.Dialogs 1.1 import QtQuick.Layouts 1.1 +import QtQuick.Dialogs 1.2 +import QtQuick.Window 2.0 +import QtQuick.Dialogs 1.1 import Qt.labs.settings 1.0 import "js/Debugger.js" as Debugger import "js/ErrorLocationFormater.js" as ErrorLocationFormater @@ -21,6 +23,75 @@ RowLayout } id: blockChainSelector + + Dialog { + id: newStateWin + modality: Qt.ApplicationModal + title: qsTr("New Project"); + + width: 320 + height: 120 + + visible: false + + contentItem: Rectangle { + anchors.fill: parent + anchors.margins: 10 + RowLayout { + anchors.verticalCenter: parent.verticalCenter + Text { + text: qsTr("Name:") + } + + Rectangle + { + Layout.preferredWidth: 250 + Layout.preferredHeight: parent.height + border.width: 1 + border.color: "#cccccc" + TextInput + { + anchors.fill: parent + id: stateName + } + } + } + RowLayout + { + anchors.bottom: parent.bottom + anchors.right: parent.right; + function acceptAndClose() + { + var item = projectModel.stateListModel.createDefaultState(); + item.title = stateName.text + projectModel.stateListModel.appendState(item) + projectModel.stateListModel.save() + close() + scenarioList.currentIndex = projectModel.stateListModel.count - 1 + } + + function close() + { + newStateWin.close() + stateName.text = "" + } + + Button { + id: okButton; + enabled: stateName.text !== "" + text: qsTr("OK"); + onClicked: { + parent.acceptAndClose(); + } + } + Button { + text: qsTr("Cancel"); + onClicked: parent.close(); + } + } + } + } + ComboBox { id: scenarioList @@ -40,7 +111,7 @@ RowLayout Row { - Layout.preferredWidth: 100 * 3 + Layout.preferredWidth: 100 * 4 Layout.preferredHeight: 30 spacing: 0 ScenarioButton { @@ -87,5 +158,18 @@ RowLayout buttonShortcut: "" sourceImg: "qrc:/qml/img/duplicateicon@2x.png" } + + ScenarioButton { + id: addScenario + width: 100 + height: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/plus.png" + onClicked: { + newStateWin.open() + } + text: qsTr("New") + } } + } From a96ed0da181d4a4afe618c8a543fdb4b49a00d2c Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 10 Jun 2015 09:40:39 +0200 Subject: [PATCH 10/40] - bug fixes - support for old projects --- mix/ClientModel.cpp | 19 ++++++++++++++- mix/qml/Block.qml | 2 +- mix/qml/BlockChain.qml | 45 ++++++++++++++++++++++++++++------- mix/qml/StateListModel.qml | 34 +++++++++++++++++++------- mix/qml/TransactionDialog.qml | 2 +- 5 files changed, 81 insertions(+), 21 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index c834ca5c7..a5936d910 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -431,12 +431,16 @@ std::pair ClientModel::resolvePair(QString const& _contractId) QStringList values = ret.first.remove("<").remove(">").split(" - "); ret = std::make_pair(values[0], values[1].toUInt()); } + if (_contractId.startsWith("0x")) + ret = std::make_pair(_contractId, -2); return ret; } QString ClientModel::resolveToken(std::pair const& _value) { - if (m_contractAddresses.size() > 0) + if (_value.second == -2) + return _value.first; + else if (m_contractAddresses.size() > 0) return QString::fromStdString("0x" + dev::toHex(m_contractAddresses[_value].ref())); else return _value.first; @@ -737,6 +741,8 @@ void ClientModel::onNewTransaction() CompiledContract const& compilerRes = m_codeModel->contract(contractAddressIter->second); const QContractDefinition* def = compilerRes.contract(); contract = def->name(); + if (creation) + function = contract; if (abi) { QFunctionDefinition const* funcDef = def->getFunction(functionHash); @@ -818,6 +824,17 @@ void ClientModel::onNewTransaction() label = contract + "." + function + "()"; else label = contract; + + if (!creation) + for (auto const& ctr: m_contractAddresses) + { + if (ctr.second == tr.address) + { + contract = "<" + ctr.first.first + " - " + QString::number(ctr.first.second) + ">"; + break; + } + } + RecordLogEntry* log = new RecordLogEntry(recordIndex, transactionIndex, contract, function, value, address, returned, tr.isCall(), RecordLogEntry::RecordType::Transaction, gasUsed, sender, label, inputParameters, logs); QQmlEngine::setObjectOwnership(log, QQmlEngine::JavaScriptOwnership); diff --git a/mix/qml/Block.qml b/mix/qml/Block.qml index b56b1f4d0..576cc5215 100644 --- a/mix/qml/Block.qml +++ b/mix/qml/Block.qml @@ -297,7 +297,7 @@ ColumnLayout anchors.fill: parent onClicked: { - if (transactions.get(index).recordIndex) + if (transactions.get(index).recordIndex !== undefined) { debugTrRequested = [ blockIndex, index ] clientModel.debugRecord(transactions.get(index).recordIndex); diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml index 5efdf8a60..ea5a09cb5 100644 --- a/mix/qml/BlockChain.qml +++ b/mix/qml/BlockChain.qml @@ -230,7 +230,9 @@ ColumnLayout { if (ensureNotFuturetime.running) return; reBuildNeeded.stop() + console.log("model block length " + model.blocks.length) var retBlocks = []; + var bAdded = 0; for (var j = 0; j < model.blocks.length; j++) { var b = model.blocks[j]; @@ -243,13 +245,30 @@ ColumnLayout { for (var k = 0; k < model.blocks[j].transactions.length; k++) { if (blockModel.get(j).transactions.get(k).saveStatus) - block.transactions.push(model.blocks[j].transactions[k]); + { + var tr = model.blocks[j].transactions[k] + tr.saveStatus = true + block.transactions.push(tr); + } + } if (block.transactions.length > 0) + { + bAdded++ + block.number = bAdded + block.status = "mined" retBlocks.push(block) + } + } if (retBlocks.length === 0) retBlocks.push(projectModel.stateListModel.createEmptyBlock()) + else + { + var last = retBlocks[retBlocks.length - 1] + last.number = -1 + last.status = "pending" + } model.blocks = retBlocks blockModel.clear() @@ -289,8 +308,14 @@ ColumnLayout { onClicked: { var lastBlock = model.blocks[model.blocks.length - 1]; + console.log(lastBlock.status + "!!!") if (lastBlock.status === "mined") - model.blocks.push(projectModel.stateListModel.createEmptyBlock()); + { + var newblock = projectModel.stateListModel.createEmptyBlock() + blockModel.appendBlock(newblock) + model.blocks.push(newblock); + } + var item = TransactionHelper.defaultTransaction() transactionDialog.stateAccounts = model.accounts transactionDialog.execute = true @@ -352,6 +377,7 @@ ColumnLayout { target: clientModel onNewBlock: { + console.log("new Block!!") if (!clientModel.running) { var lastBlock = model.blocks[model.blocks.length - 1] @@ -370,15 +396,12 @@ ColumnLayout { { var blockIndex = parseInt(_r.transactionIndex.split(":")[0]) - 1 var trIndex = parseInt(_r.transactionIndex.split(":")[1]) - console.log("kkkk" + blockIndex) - console.log(trIndex) if (blockIndex <= model.blocks.length - 1) { var item = model.blocks[blockIndex] if (trIndex <= item.transactions.length - 1) { var tr = item.transactions[trIndex] - console.log(JSON.stringify(_r)) tr.returned = _r.returned tr.recordIndex = _r.recordIndex tr.logs = _r.logs @@ -408,6 +431,7 @@ ColumnLayout { itemTr.sender = _r.sender itemTr.recordIndex = _r.recordIndex itemTr.logs = _r.logs + console.log(JSON.stringify(itemTr)) model.blocks[model.blocks.length - 1].transactions.push(itemTr) blockModel.appendTransaction(itemTr) } @@ -421,7 +445,6 @@ ColumnLayout { text: qsTr("New Account") onClicked: { model.accounts.push(projectModel.stateListModel.newAccount("1000000", QEther.Ether)) - chainChanged() } Layout.preferredWidth: 100 Layout.preferredHeight: 30 @@ -438,11 +461,15 @@ ColumnLayout { var item = transactionDialog.getItem() if (execute) { + console.log("cc " + model.blocks.length) var lastBlock = model.blocks[model.blocks.length - 1]; + console.log("mined?" + lastBlock.status) if (lastBlock.status === "mined") - model.blocks.push(projectModel.stateListModel.createEmptyBlock()); - model.blocks[model.blocks.length - 1].transactions.push(item) - blockModel.appendTransaction(item) + { + var newBlock = projectModel.stateListModel.createEmptyBlock(); + model.blocks.push(newBlock); + blockModel.appendBlock(newBlock) + } if (!clientModel.running) clientModel.executeTr(item) } diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index cb9688524..f056acc22 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -16,19 +16,32 @@ Item { property string defaultAccount: "cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074" //support for old project function fromPlainStateItem(s) { - console.log("ggg " + s) if (!s.accounts) s.accounts = [stateListModel.newAccount("1000000", QEther.Ether, defaultAccount)]; //support for old project if (!s.contracts) s.contracts = []; - return { - title: s.title, - transactions: s.transactions.filter(function(t) { return !t.stdContract; }).map(fromPlainTransactionItem), //support old projects by filtering std contracts - blocks: s.blocks.map(fromPlainBlockItem), - accounts: s.accounts.map(fromPlainAccountItem), - contracts: s.contracts.map(fromPlainAccountItem), - miner: s.miner - }; + + var ret = {}; + ret.title = s.title; + ret.transactions = s.transactions.filter(function(t) { return !t.stdContract; }).map(fromPlainTransactionItem); //support old projects by filtering std contracts + if (s.blocks) + ret.blocks = s.blocks.map(fromPlainBlockItem); + ret.accounts = s.accounts.map(fromPlainAccountItem); + ret.contracts = s.contracts.map(fromPlainAccountItem); + ret.miner = s.miner; + + // support old projects + if (!ret.blocks) + { + ret.blocks = [{ + hash: "", + number: -1, + transactions: [], + status: "pending" + }] + for (var j in ret.transactions) + ret.blocks[0].transactions.push(fromPlainTransactionItem(toPlainTransactionItem(ret.transactions[j]))) + } } function fromPlainAccountItem(t) @@ -64,6 +77,9 @@ Item { saveStatus: t.saveStatus }; + if (r.saveStatus === undefined) + r.saveStatus = true + if (r.isFunctionCall === undefined) r.isFunctionCall = true; diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index b53c7c787..56810b375 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -64,7 +64,7 @@ Dialog { for (var c in contracts) { contractsModel.append({ cid: c, text: contracts[c].contract.name }); if (contracts[c].contract.name === contractId) - contractIndex = contractsModel.count - 1; + contractIndex = contractsModel.count - 1; } if (contractIndex == -1 && contractsModel.count > 0) From ec62858be10594e2d3220e2455561e70355abea2 Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 10 Jun 2015 10:57:37 +0200 Subject: [PATCH 11/40] cosmetic changes --- mix/ClientModel.cpp | 2 +- mix/ClientModel.h | 57 +- mix/ContractCallDataEncoder.cpp | 2 +- mix/ContractCallDataEncoder.h | 2 +- mix/MachineStates.h | 86 +-- mix/MixClient.cpp | 55 +- mix/MixClient.h | 5 +- mix/QContractDefinition.cpp | 2 +- mix/main.cpp | 4 +- mix/qml/Application.qml | 10 +- mix/qml/Block.qml | 614 ++++++++++----------- mix/qml/BlockChain.qml | 931 ++++++++++++++++---------------- mix/qml/Debugger.qml | 144 ++--- mix/qml/MainContent.qml | 108 ++-- mix/qml/QAddressView.qml | 3 - mix/qml/ScenarioButton.qml | 112 ++-- mix/qml/ScenarioExecution.qml | 78 +-- mix/qml/ScenarioLoader.qml | 318 +++++------ mix/qml/StateListModel.qml | 241 +++++---- mix/qml/StructView.qml | 2 +- mix/qml/TransactionDialog.qml | 20 +- mix/qml/js/ProjectModel.js | 110 ++-- mix/qml/js/TransactionHelper.js | 4 +- 23 files changed, 1422 insertions(+), 1488 deletions(-) diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 9c3ab5832..1da664fbe 100644 --- a/mix/ClientModel.cpp +++ b/mix/ClientModel.cpp @@ -438,7 +438,7 @@ std::pair ClientModel::resolvePair(QString const& _contractId) QString ClientModel::resolveToken(std::pair const& _value) { - if (_value.second == -2) + if (_value.second == -2) //-2: first contains a real address return _value.first; else if (m_contractAddresses.size() > 0) return QString::fromStdString("0x" + dev::toHex(m_contractAddresses[_value].ref())); diff --git a/mix/ClientModel.h b/mix/ClientModel.h index c062aa4a7..32348b603 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -109,14 +109,14 @@ class RecordLogEntry: public QObject Q_PROPERTY(RecordType type MEMBER m_type CONSTANT) /// Gas used Q_PROPERTY(QString gasUsed MEMBER m_gasUsed CONSTANT) - /// Sender - Q_PROPERTY(QString sender MEMBER m_sender CONSTANT) - /// label - Q_PROPERTY(QString label MEMBER m_label CONSTANT) - /// input parameters - Q_PROPERTY(QVariantMap parameters MEMBER m_inputParameters CONSTANT) - /// logs - Q_PROPERTY(QVariantList logs MEMBER m_logs CONSTANT) + /// Sender + Q_PROPERTY(QString sender MEMBER m_sender CONSTANT) + /// label + Q_PROPERTY(QString label MEMBER m_label CONSTANT) + /// input parameters + Q_PROPERTY(QVariantMap parameters MEMBER m_inputParameters CONSTANT) + /// logs + Q_PROPERTY(QVariantList logs MEMBER m_logs CONSTANT) public: enum RecordType @@ -127,10 +127,10 @@ public: RecordLogEntry(): m_recordIndex(0), m_call(false), m_type(RecordType::Transaction) {} - RecordLogEntry(unsigned _recordIndex, QString _transactionIndex, QString _contract, QString _function, QString _value, QString _address, QString _returned, bool _call, RecordType _type, QString _gasUsed, - QString _sender, QString _label, QVariantMap _inputParameters, QVariantList _logs): - m_recordIndex(_recordIndex), m_transactionIndex(_transactionIndex), m_contract(_contract), m_function(_function), m_value(_value), m_address(_address), m_returned(_returned), m_call(_call), m_type(_type), m_gasUsed(_gasUsed), - m_sender(_sender), m_label(_label), m_inputParameters(_inputParameters), m_logs(_logs) {} + RecordLogEntry(unsigned _recordIndex, QString _transactionIndex, QString _contract, QString _function, QString _value, QString _address, QString _returned, bool _call, RecordType _type, QString _gasUsed, + QString _sender, QString _label, QVariantMap _inputParameters, QVariantList _logs): + m_recordIndex(_recordIndex), m_transactionIndex(_transactionIndex), m_contract(_contract), m_function(_function), m_value(_value), m_address(_address), m_returned(_returned), m_call(_call), m_type(_type), m_gasUsed(_gasUsed), + m_sender(_sender), m_label(_label), m_inputParameters(_inputParameters), m_logs(_logs) {} private: unsigned m_recordIndex; @@ -143,10 +143,10 @@ private: bool m_call; RecordType m_type; QString m_gasUsed; - QString m_sender; - QString m_label; - QVariantMap m_inputParameters; - QVariantList m_logs; + QString m_sender; + QString m_label; + QVariantMap m_inputParameters; + QVariantList m_logs; }; /** @@ -185,14 +185,11 @@ public: Q_INVOKABLE QString toHex(QString const& _int); public slots: - /// Setup state, run transaction sequence, show debugger for the last transaction + /// Setup scenario, run transaction sequence, show debugger for the last transaction /// @param _state JS object with state configuration - //void setupState(QVariantMap _state); - /// Setup scenario, run transaction sequence, show debugger for the last transaction - /// @param _state JS object with state configuration - void setupScenario(QVariantMap _scenario); - /// Execute the given @param _tr on the curret state - void executeTr(QVariantMap _tr); + void setupScenario(QVariantMap _scenario); + /// Execute the given @param _tr on the current state + void executeTr(QVariantMap _tr); /// Show the debugger for a specified record Q_INVOKABLE void debugRecord(unsigned _index); /// Show the debugger for an empty record @@ -244,7 +241,7 @@ private: RecordLogEntry* lastBlock() const; QVariantMap contractAddresses() const; QVariantList gasCosts() const; - void executeSequence(std::vector const& _sequence); + void executeSequence(std::vector const& _sequence); dev::Address deployContract(bytes const& _code, TransactionSettings const& _tr = TransactionSettings()); void callAddress(Address const& _contract, bytes const& _data, TransactionSettings const& _tr); void onNewTransaction(); @@ -255,9 +252,9 @@ private: std::pair retrieveToken(QString const& _value); std::pair resolvePair(QString const& _contractId); QVariant formatStorageValue(SolidityType const& _type, std::unordered_map const& _storage, unsigned _offset, dev::u256 const& _slot); - void processNextTransactions(); - void finalizeBlock(); - void stopExecution(); + void processNextTransactions(); + void finalizeBlock(); + void stopExecution(); void setupExecutionChain(); std::atomic m_running; @@ -267,7 +264,7 @@ private: std::unique_ptr m_rpcConnector; std::unique_ptr m_web3Server; std::shared_ptr m_ethAccounts; - std::unordered_map m_accounts; + std::unordered_map m_accounts; std::vector m_accountsSecret; QList m_gasCosts; std::map, Address> m_contractAddresses; @@ -275,8 +272,8 @@ private: std::map m_stdContractAddresses; std::map m_stdContractNames; CodeModel* m_codeModel = nullptr; - QList m_queueTransactions; - QVariantMap m_currentScenario; + QList m_queueTransactions; + QVariantMap m_currentScenario; mutable boost::shared_mutex x_queueTransactions; }; diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 553c5e075..d805822aa 100644 --- a/mix/ContractCallDataEncoder.cpp +++ b/mix/ContractCallDataEncoder.cpp @@ -245,7 +245,7 @@ QStringList ContractCallDataEncoder::decode(QList const& value.populate(&rawParam); value = value.cropped(32); QVariableDeclaration* dec = static_cast(_returnParameters.at(k)); - SolidityType const& type = dec->type()->type(); + SolidityType const& type = dec->type()->type(); r.append(decode(type, rawParam).toString()); } return r; diff --git a/mix/ContractCallDataEncoder.h b/mix/ContractCallDataEncoder.h index 748239c5b..8fcc65c0a 100644 --- a/mix/ContractCallDataEncoder.h +++ b/mix/ContractCallDataEncoder.h @@ -50,7 +50,7 @@ public: QStringList decode(QList const& _dec, bytes _value); /// Decode @param _parameter QString decode(QVariableDeclaration* const& _param, bytes _value); - /// Decode single variable + /// Decode single variable QVariant decode(SolidityType const& _type, bytes const& _value); /// Get all encoded data encoded by encode function. bytes encodedData(); diff --git a/mix/MachineStates.h b/mix/MachineStates.h index 1b50c062b..9a9acecf4 100644 --- a/mix/MachineStates.h +++ b/mix/MachineStates.h @@ -37,59 +37,59 @@ namespace dev namespace mix { - /** +/** * @brief Store information about a machine state. */ - struct MachineState - { - uint64_t steps; - dev::u256 curPC; - dev::eth::Instruction inst; - dev::bigint newMemSize; - dev::u256 gas; - dev::u256s stack; - dev::bytes memory; - dev::bigint gasCost; - std::unordered_map storage; - std::vector levels; - unsigned codeIndex; - unsigned dataIndex; - }; +struct MachineState +{ + uint64_t steps; + dev::u256 curPC; + dev::eth::Instruction inst; + dev::bigint newMemSize; + dev::u256 gas; + dev::u256s stack; + dev::bytes memory; + dev::bigint gasCost; + std::unordered_map storage; + std::vector levels; + unsigned codeIndex; + unsigned dataIndex; +}; - /** +/** * @brief Executed conract code info */ - struct MachineCode - { - dev::Address address; - bytes code; - }; +struct MachineCode +{ + dev::Address address; + bytes code; +}; - /** +/** * @brief Store information about a machine states. */ - struct ExecutionResult - { - ExecutionResult(): transactionIndex(std::numeric_limits::max()) {} +struct ExecutionResult +{ + ExecutionResult(): transactionIndex(std::numeric_limits::max()) {} - std::vector machineStates; - std::vector transactionData; - std::vector executionCode; - dev::eth::ExecutionResult result; - dev::Address address; - dev::Address sender; - dev::Address contractAddress; - dev::u256 value; - dev::u256 gasUsed; - unsigned transactionIndex; - unsigned executonIndex = 0; - bytes inputParameters; - eth::LocalisedLogEntries logs; + std::vector machineStates; + std::vector transactionData; + std::vector executionCode; + dev::eth::ExecutionResult result; + dev::Address address; + dev::Address sender; + dev::Address contractAddress; + dev::u256 value; + dev::u256 gasUsed; + unsigned transactionIndex; + unsigned executonIndex = 0; + bytes inputParameters; + eth::LocalisedLogEntries logs; - bool isCall() const { return transactionIndex == std::numeric_limits::max(); } - bool isConstructor() const { return !isCall() && !address; } - }; + bool isCall() const { return transactionIndex == std::numeric_limits::max(); } + bool isConstructor() const { return !isCall() && !address; } +}; - using ExecutionResults = std::vector; +using ExecutionResults = std::vector; } } diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 62d6636c2..31b4772b4 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -73,25 +73,11 @@ MixClient::MixClient(std::string const& _dbPath): resetState(std::unordered_map()); } -MixClient::~MixClient() -{ -} - -LocalisedLogEntries MixClient::logs() -{ - return m_watches.at(0).changes; -} - void MixClient::resetState(std::unordered_map const& _accounts, Secret const& _miner) { WriteGuard l(x_state); Guard fl(x_filtersWatches); - m_filters.clear(); - m_watches.clear(); - //LogFilter filter; - //m_filters.insert(std::make_pair(filter.sha3(), filter)); - //m_watches.insert(std::make_pair(0, ClientWatch(filter.sha3(), Reaping::Automatic))); m_stateDB = OverlayDB(); SecureTrieDB accountState(&m_stateDB); @@ -261,39 +247,15 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c if (t.isCreation() && _state.code(d.contractAddress).empty()) BOOST_THROW_EXCEPTION(OutOfGas() << errinfo_comment("Not enough gas for contract deployment")); d.gasUsed = er.gasUsed + er.gasRefunded + er.gasForDeposit + c_callStipend; - // collect watches - h256Set changed; - Guard l(x_filtersWatches); LocalisedLogEntries logs; - //for (unsigned i = 0; i < _state.pending().size(); ++i) - //{ TransactionReceipt const& tr = _state.receipt(_state.pending().size() - 1); auto trHash = _state.pending().at(_state.pending().size() - 1).sha3(); - //for (std::pair& installedFilter: m_filters) - //{ - LogEntries le = tr.log(); // installedFilter.second.filter.matches(tr); + LogEntries le = tr.log(); if (le.size()) for (unsigned j = 0; j < le.size(); ++j) logs.insert(logs.begin(), LocalisedLogEntry(le[j], bc().number() + 1, trHash)); - //} - //} - - /*if ((unsigned)i.second.filter.latest() > bc().number()) - { - // acceptable number. - auto m = i.second.filter.matches(_state.receipt(_state.pending().size() - 1)); - if (m.size()) - { - // filter catches them - for (LogEntry const& l: m) - i.second.changes.push_back(LocalisedLogEntry(l, bc().number() + 1)); - changed.insert(i.first); - } - }*/ - changed.insert(dev::eth::PendingChangedFilter); d.logs = logs; - //noteChanged(changed); } WriteGuard l(x_executions); m_executions.emplace_back(std::move(d)); @@ -308,7 +270,6 @@ void MixClient::mine() m_state.sync(bc()); m_startState = m_state; h256Set changed { dev::eth::PendingChangedFilter, dev::eth::ChainChangedFilter }; - //noteChanged(changed); } ExecutionResult MixClient::lastExecution() const @@ -395,20 +356,6 @@ dev::eth::ExecutionResult MixClient::create(Address const& _from, u256 _value, b return lastExecution().result; } -/*void MixClient::noteChanged(h256Set const& _filters) -{ - for (auto& i: m_watches) - if (_filters.count(i.second.id)) - { - if (m_filters.count(i.second.id)) - i.second.changes += m_filters.at(i.second.id).changes; - else - i.second.changes.push_back(LocalisedLogEntry(SpecialLogEntry, 0)); - } - for (auto& i: m_filters) - i.second.changes.clear(); -}*/ - eth::BlockInfo MixClient::blockInfo() const { ReadGuard l(x_state); diff --git a/mix/MixClient.h b/mix/MixClient.h index 4e05e5104..afb9f5430 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -77,8 +77,6 @@ public: using Interface::blockInfo; // to remove warning about hiding virtual function eth::BlockInfo blockInfo() const; - dev::eth::LocalisedLogEntries logs(); - protected: /// ClientBase methods using ClientBase::asOf; @@ -91,10 +89,9 @@ protected: private: void executeTransaction(dev::eth::Transaction const& _t, eth::State& _state, bool _call, bool _gasAuto, dev::Secret const& _secret = dev::Secret()); - //void noteChanged(h256Set const& _filters); dev::eth::Transaction replaceGas(dev::eth::Transaction const& _t, dev::u256 const& _gas, dev::Secret const& _secret = dev::Secret()); - eth::State m_state; + eth::State m_state; eth::State m_startState; OverlayDB m_stateDB; std::unique_ptr m_bc; diff --git a/mix/QContractDefinition.cpp b/mix/QContractDefinition.cpp index fe05e80be..f4022d1ff 100644 --- a/mix/QContractDefinition.cpp +++ b/mix/QContractDefinition.cpp @@ -53,7 +53,7 @@ QContractDefinition::QContractDefinition(QObject* _parent, dev::solidity::Contra } - for (auto const& it: _contract->getEvents()) + for (auto const& it: _contract->getEvents()) m_events.append(new QFunctionDefinition(parent, it)); } diff --git a/mix/main.cpp b/mix/main.cpp index b4206ec51..78b5261ac 100644 --- a/mix/main.cpp +++ b/mix/main.cpp @@ -32,9 +32,9 @@ int main(int _argc, char* _argv[]) { try { - MixApplication::initialize(); + MixApplication::initialize(); MixApplication app(_argc, _argv); - return app.exec(); + return app.exec(); } catch (boost::exception const& _e) { diff --git a/mix/qml/Application.qml b/mix/qml/Application.qml index 509e2e178..61a2e09b1 100644 --- a/mix/qml/Application.qml +++ b/mix/qml/Application.qml @@ -205,14 +205,14 @@ ApplicationWindow { enabled: codeModel.hasContract && !clientModel.running } - Action { + Action { id: toggleAssemblyDebuggingAction text: qsTr("Show VM Code") shortcut: "Ctrl+Alt+V" - onTriggered: mainContent.debuggerPanel.assemblyMode = !mainContent.debuggerPanel.assemblyMode; - checked: mainContent.debuggerPanel.assemblyMode; + onTriggered: mainContent.debuggerPanel.assemblyMode = !mainContent.debuggerPanel.assemblyMode; + checked: mainContent.debuggerPanel.assemblyMode; enabled: true - } + } Action { id: toggleWebPreviewAction @@ -221,7 +221,7 @@ ApplicationWindow { checkable: true checked: mainContent.webViewVisible onTriggered: mainContent.toggleWebPreview(); - } + } Action { id: toggleProjectNavigatorAction diff --git a/mix/qml/Block.qml b/mix/qml/Block.qml index 576cc5215..6fb274ccd 100644 --- a/mix/qml/Block.qml +++ b/mix/qml/Block.qml @@ -10,337 +10,337 @@ import "." ColumnLayout { - id: root - property variant transactions - property string status - property int number - property int blockWidth: Layout.preferredWidth - statusWidth - horizontalMargin - property int horizontalMargin: 10 - property int trHeight: 30 - spacing: 0 - property int openedTr: 0 - property int blockIndex - property variant scenario + id: root + property variant transactions + property string status + property int number + property int blockWidth: Layout.preferredWidth - statusWidth - horizontalMargin + property int horizontalMargin: 10 + property int trHeight: 30 + spacing: 0 + property int openedTr: 0 + property int blockIndex + property variant scenario - function calculateHeight() - { - if (transactions) - { - if (index >= 0) - return 30 + 30 * transactions.count + openedTr - else - return 30 - } - else - return 30 - } + function calculateHeight() + { + if (transactions) + { + if (index >= 0) + return 30 + 30 * transactions.count + openedTr + else + return 30 + } + else + return 30 + } - onOpenedTrChanged: - { - Layout.preferredHeight = calculateHeight() - height = calculateHeight() - } + onOpenedTrChanged: + { + Layout.preferredHeight = calculateHeight() + height = calculateHeight() + } - RowLayout - { - Layout.preferredHeight: trHeight - Layout.preferredWidth: blockWidth - id: rowHeader - Rectangle - { - color: "#DEDCDC" - Layout.preferredWidth: blockWidth - Layout.preferredHeight: trHeight - radius: 4 - anchors.left: parent.left - anchors.leftMargin: statusWidth + 5 - Label { - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: horizontalMargin - text: - { - if (status === "mined") - return qsTr("BLOCK") + " " + number - else - return qsTr("BLOCK") + " pending" - } - } - } - } + RowLayout + { + Layout.preferredHeight: trHeight + Layout.preferredWidth: blockWidth + id: rowHeader + Rectangle + { + color: "#DEDCDC" + Layout.preferredWidth: blockWidth + Layout.preferredHeight: trHeight + radius: 4 + anchors.left: parent.left + anchors.leftMargin: statusWidth + 5 + Label { + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: horizontalMargin + text: + { + if (status === "mined") + return qsTr("BLOCK") + " " + number + else + return qsTr("BLOCK") + " pending" + } + } + } + } - Repeater // List of transactions - { - id: transactionRepeater - model: transactions + Repeater // List of transactions + { + id: transactionRepeater + model: transactions - RowLayout - { - id: rowTransaction - Layout.preferredHeight: trHeight - function displayContent() - { - logsText.text = "" - if (index >= 0 && transactions.get(index).logs && transactions.get(index).logs.count) - { - for (var k = 0; k < transactions.get(index).logs.count; k++) - { - var log = transactions.get(index).logs.get(k) - if (log.name) - logsText.text += log.name + ":\n" - else - logsText.text += "log:\n" + RowLayout + { + id: rowTransaction + Layout.preferredHeight: trHeight + function displayContent() + { + logsText.text = "" + if (index >= 0 && transactions.get(index).logs && transactions.get(index).logs.count) + { + for (var k = 0; k < transactions.get(index).logs.count; k++) + { + var log = transactions.get(index).logs.get(k) + if (log.name) + logsText.text += log.name + ":\n" + else + logsText.text += "log:\n" - if (log.param) - for (var i = 0; i < log.param.count; i++) - { - var p = log.param.get(i) - logsText.text += p.name + " = " + p.value + " - indexed:" + p.indexed + "\n" - } - else{ - logsText.text += "From : " + log.address + "\n" - } - } - logsText.text += "\n\n" - } - rowDetailedContent.visible = !rowDetailedContent.visible - } + if (log.param) + for (var i = 0; i < log.param.count; i++) + { + var p = log.param.get(i) + logsText.text += p.name + " = " + p.value + " - indexed:" + p.indexed + "\n" + } + else{ + logsText.text += "From : " + log.address + "\n" + } + } + logsText.text += "\n\n" + } + rowDetailedContent.visible = !rowDetailedContent.visible + } - Rectangle - { - id: trSaveStatus - Layout.preferredWidth: statusWidth - Layout.preferredHeight: trHeight - color: "transparent" - anchors.top: parent.top - property bool saveStatus + Rectangle + { + id: trSaveStatus + Layout.preferredWidth: statusWidth + Layout.preferredHeight: trHeight + color: "transparent" + anchors.top: parent.top + property bool saveStatus - Image { - id: saveStatusImage - source: "qrc:/qml/img/recyclediscard@2x.png" - width: statusWidth - fillMode: Image.PreserveAspectFit - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - } + Image { + id: saveStatusImage + source: "qrc:/qml/img/recyclediscard@2x.png" + width: statusWidth + fillMode: Image.PreserveAspectFit + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + } - Component.onCompleted: - { - if (index >= 0) - saveStatus = transactions.get(index).saveStatus - } + Component.onCompleted: + { + if (index >= 0) + saveStatus = transactions.get(index).saveStatus + } - onSaveStatusChanged: - { - if (saveStatus) - saveStatusImage.source = "qrc:/qml/img/recyclekeep@2x.png" - else - saveStatusImage.source = "qrc:/qml/img/recyclediscard@2x.png" + onSaveStatusChanged: + { + if (saveStatus) + saveStatusImage.source = "qrc:/qml/img/recyclekeep@2x.png" + else + saveStatusImage.source = "qrc:/qml/img/recyclediscard@2x.png" - if (index >= 0) - transactions.get(index).saveStatus = saveStatus - } + if (index >= 0) + transactions.get(index).saveStatus = saveStatus + } - MouseArea { - id: statusMouseArea - anchors.fill: parent - onClicked: - { - parent.saveStatus = !parent.saveStatus - } - } - } + MouseArea { + id: statusMouseArea + anchors.fill: parent + onClicked: + { + parent.saveStatus = !parent.saveStatus + } + } + } - Rectangle - { - Layout.preferredWidth: blockWidth - Layout.preferredHeight: parent.height - color: "#DEDCDC" - id: rowContentTr - anchors.top: parent.top - ColumnLayout - { - anchors.top: parent.top - spacing: 10 - RowLayout - { - anchors.top: parent.top - anchors.verticalCenter: parent.verticalCenter - spacing: cellSpacing - Text - { - id: hash - anchors.left: parent.left - anchors.leftMargin: horizontalMargin - Layout.preferredWidth: fromWidth - elide: Text.ElideRight - maximumLineCount: 1 - text: { - if (index >= 0) - return transactions.get(index).sender - else - return "" - } - } + Rectangle + { + Layout.preferredWidth: blockWidth + Layout.preferredHeight: parent.height + color: "#DEDCDC" + id: rowContentTr + anchors.top: parent.top + ColumnLayout + { + anchors.top: parent.top + spacing: 10 + RowLayout + { + anchors.top: parent.top + anchors.verticalCenter: parent.verticalCenter + spacing: cellSpacing + Text + { + id: hash + anchors.left: parent.left + anchors.leftMargin: horizontalMargin + Layout.preferredWidth: fromWidth + elide: Text.ElideRight + maximumLineCount: 1 + text: { + if (index >= 0) + return transactions.get(index).sender + else + return "" + } + } - Text - { - id: func - text: { - if (index >= 0) - parent.userFrienldyToken(transactions.get(index).label) - else - return "" - } - elide: Text.ElideRight - maximumLineCount: 1 - Layout.preferredWidth: toWidth - } + Text + { + id: func + text: { + if (index >= 0) + parent.userFrienldyToken(transactions.get(index).label) + else + return "" + } + elide: Text.ElideRight + maximumLineCount: 1 + Layout.preferredWidth: toWidth + } - function userFrienldyToken(value) - { - if (value && value.indexOf("<") === 0) - { - if (value.split("> ")[1] === " - ") - return value.split(" - ")[0].replace("<", "") - else - return value.split(" - ")[0].replace("<", "") + "." + value.split("> ")[1] + "()"; - } - else - return value - } + function userFrienldyToken(value) + { + if (value && value.indexOf("<") === 0) + { + if (value.split("> ")[1] === " - ") + return value.split(" - ")[0].replace("<", "") + else + return value.split(" - ")[0].replace("<", "") + "." + value.split("> ")[1] + "()"; + } + else + return value + } - Text - { - id: returnValue - elide: Text.ElideRight - maximumLineCount: 1 - Layout.preferredWidth: valueWidth - text: { - if (index >= 0 && transactions.get(index).returned) - return transactions.get(index).returned - else - return "" - } - } + Text + { + id: returnValue + elide: Text.ElideRight + maximumLineCount: 1 + Layout.preferredWidth: valueWidth + text: { + if (index >= 0 && transactions.get(index).returned) + return transactions.get(index).returned + else + return "" + } + } - Rectangle - { - Layout.preferredWidth: logsWidth - Layout.preferredHeight: trHeight - 10 - width: logsWidth - color: "transparent" - Text - { - id: logs - anchors.left: parent.left - anchors.leftMargin: 10 - text: { - if (index >= 0 && transactions.get(index).logs && transactions.get(index).logs.count) - return transactions.get(index).logs.count - else - return "" - } - } - MouseArea { - anchors.fill: parent - onClicked: { - rowTransaction.displayContent(); - } - } - } + Rectangle + { + Layout.preferredWidth: logsWidth + Layout.preferredHeight: trHeight - 10 + width: logsWidth + color: "transparent" + Text + { + id: logs + anchors.left: parent.left + anchors.leftMargin: 10 + text: { + if (index >= 0 && transactions.get(index).logs && transactions.get(index).logs.count) + return transactions.get(index).logs.count + else + return "" + } + } + MouseArea { + anchors.fill: parent + onClicked: { + rowTransaction.displayContent(); + } + } + } - Rectangle - { - Layout.preferredWidth: debugActionWidth - Layout.preferredHeight: trHeight - 10 - color: "transparent" + Rectangle + { + Layout.preferredWidth: debugActionWidth + Layout.preferredHeight: trHeight - 10 + color: "transparent" - Image { - source: "qrc:/qml/img/edit.png" - width: 18 - fillMode: Image.PreserveAspectFit - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - } - MouseArea - { - anchors.fill: parent - onClicked: - { - transactionDialog.stateAccounts = scenario.accounts - transactionDialog.execute = false - transactionDialog.open(index, blockIndex, transactions.get(index)) - } - } - } + Image { + source: "qrc:/qml/img/edit.png" + width: 18 + fillMode: Image.PreserveAspectFit + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + } + MouseArea + { + anchors.fill: parent + onClicked: + { + transactionDialog.stateAccounts = scenario.accounts + transactionDialog.execute = false + transactionDialog.open(index, blockIndex, transactions.get(index)) + } + } + } - Rectangle - { - Layout.preferredWidth: debugActionWidth - Layout.preferredHeight: trHeight - 10 - color: "transparent" + Rectangle + { + Layout.preferredWidth: debugActionWidth + Layout.preferredHeight: trHeight - 10 + color: "transparent" - Image { - id: debugImg - source: "qrc:/qml/img/rightarrow@2x.png" - width: statusWidth - fillMode: Image.PreserveAspectFit - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter - visible: transactions.get(index).recordIndex !== undefined - } - MouseArea - { - anchors.fill: parent - onClicked: - { - if (transactions.get(index).recordIndex !== undefined) - { - debugTrRequested = [ blockIndex, index ] - clientModel.debugRecord(transactions.get(index).recordIndex); - } - } - } - } - } + Image { + id: debugImg + source: "qrc:/qml/img/rightarrow@2x.png" + width: statusWidth + fillMode: Image.PreserveAspectFit + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + visible: transactions.get(index).recordIndex !== undefined + } + MouseArea + { + anchors.fill: parent + onClicked: + { + if (transactions.get(index).recordIndex !== undefined) + { + debugTrRequested = [ blockIndex, index ] + clientModel.debugRecord(transactions.get(index).recordIndex); + } + } + } + } + } - RowLayout - { - id: rowDetailedContent - visible: false - Layout.preferredHeight:{ - if (index >= 0 && transactions.get(index).logs) - return 100 * transactions.get(index).logs.count - else - return 100 - } - onVisibleChanged: - { - var lognb = transactions.get(index).logs.count - if (visible) - { - rowContentTr.Layout.preferredHeight = trHeight + 100 * lognb - openedTr += 100 * lognb - } - else - { - rowContentTr.Layout.preferredHeight = trHeight - openedTr -= 100 * lognb - } - } + RowLayout + { + id: rowDetailedContent + visible: false + Layout.preferredHeight:{ + if (index >= 0 && transactions.get(index).logs) + return 100 * transactions.get(index).logs.count + else + return 100 + } + onVisibleChanged: + { + var lognb = transactions.get(index).logs.count + if (visible) + { + rowContentTr.Layout.preferredHeight = trHeight + 100 * lognb + openedTr += 100 * lognb + } + else + { + rowContentTr.Layout.preferredHeight = trHeight + openedTr -= 100 * lognb + } + } - Text { - anchors.left: parent.left - anchors.leftMargin: horizontalMargin - id: logsText - } - } - } - } - } - } + Text { + anchors.left: parent.left + anchors.leftMargin: horizontalMargin + id: logsText + } + } + } + } + } + } } diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml index 69e2bbf34..d3fad6fda 100644 --- a/mix/qml/BlockChain.qml +++ b/mix/qml/BlockChain.qml @@ -12,474 +12,469 @@ import "js/QEtherHelper.js" as QEtherHelper import "." ColumnLayout { - id: blockChainPanel - property variant model - spacing: 0 - property int previousWidth - property variant debugTrRequested: [] - signal chainChanged - - onChainChanged: { - reBuildNeeded.start() - } - - onWidthChanged: - { - - if (width <= 630 || previousWidth <= 630) - { - fromWidth = 100 - toWidth = 100 - valueWidth = 200 - } - else - { - var diff = (width - previousWidth) / 3; - fromWidth = fromWidth + diff < 100 ? 100 : fromWidth + diff - toWidth = toWidth + diff < 100 ? 100 : toWidth + diff - valueWidth = valueWidth + diff < 200 ? 200 : valueWidth + diff - } - previousWidth = width - } - - function load(scenario) - { - if (!scenario) - return; - if (model) - chainChanged() - model = scenario - blockModel.clear() - for (var b in model.blocks) - blockModel.append(model.blocks[b]) - previousWidth = width - } - - property int statusWidth: 30 - property int fromWidth: 100 - property int toWidth: 100 - property int valueWidth: 200 - property int logsWidth: 50 - property int debugActionWidth: 50 - property int horizontalMargin: 10 - property int cellSpacing: 10 - - RowLayout - { - id: header - spacing: 0 - Layout.preferredHeight: 25 - Image { - id: debugImage - source: "qrc:/qml/img/recycleicon@2x.png" - Layout.preferredWidth: statusWidth - Layout.preferredHeight: 25 - fillMode: Image.PreserveAspectFit - } - Rectangle - { - Layout.preferredWidth: fromWidth + cellSpacing - Label - { - anchors.verticalCenter: parent.verticalCenter - text: "From" - anchors.left: parent.left - anchors.leftMargin: horizontalMargin + 5 - } - } - Label - { - text: "To" - Layout.preferredWidth: toWidth + cellSpacing - } - Label - { - text: "Value" - Layout.preferredWidth: valueWidth + cellSpacing - } - Label - { - text: "Logs" - Layout.preferredWidth: logsWidth + cellSpacing - } - Label - { - text: "" - Layout.preferredWidth: debugActionWidth - } - } - - Rectangle - { - Layout.preferredHeight: 500 - Layout.preferredWidth: parent.width - border.color: "#cccccc" - border.width: 2 - color: "white" - ScrollView - { - id: blockChainScrollView - anchors.fill: parent - anchors.topMargin: 10 - ColumnLayout - { - id: blockChainLayout - width: parent.width - spacing: 10 - Repeater // List of blocks - { - id: blockChainRepeater - model: blockModel - Block - { - scenario: blockChainPanel.model - Layout.preferredWidth: blockChainScrollView.width - Layout.preferredHeight: - { - return calculateHeight() - } - blockIndex: index - transactions: - { - if (index >= 0) - return blockModel.get(index).transactions - else - return [] - } - - status: - { - if (index >= 0) - return blockModel.get(index).status - else - return "" - } - - number: - { - if (index >= 0) - return blockModel.get(index).number - else - return 0 - } - } - } - } - } - } - - ListModel - { - id: blockModel - - function appendBlock(block) - { - blockModel.append(block); - } - - function appendTransaction(tr) - { - blockModel.get(blockModel.count - 1).transactions.append(tr) - } - - function removeTransaction(blockIndex, trIndex) - { - blockModel.get(blockIndex).transactions.remove(trIndex) - } - - function removeLastBlock() - { - blockModel.remove(blockModel.count - 1) - } - - function removeBlock(index) - { - blockModel.remove(index) - } - - function getTransaction(block, tr) - { - return blockModel.get(block).transactions.get(tr) - } - - function setTransaction(blockIndex, trIndex, tr) - { - blockModel.get(blockIndex).transactions.set(trIndex, tr) - } - - function setTransactionProperty(blockIndex, trIndex, propertyName, value) - { - blockModel.get(blockIndex).transactions.set(trIndex, { propertyName: value }) - } - } - - Rectangle - { - Layout.preferredWidth: parent.width - RowLayout - { - width: 4 * 100 - anchors.top: parent.top - anchors.topMargin: 10 - spacing: 0 - ScenarioButton { - id: rebuild - text: qsTr("Rebuild") - onClicked: - { - if (ensureNotFuturetime.running) - return; - reBuildNeeded.stop() - var retBlocks = []; - var bAdded = 0; - for (var j = 0; j < model.blocks.length; j++) - { - var b = model.blocks[j]; - var block = { - hash: b.hash, - number: b.number, - transactions: [], - status: b.status - } - for (var k = 0; k < model.blocks[j].transactions.length; k++) - { - if (blockModel.get(j).transactions.get(k).saveStatus) - { - var tr = model.blocks[j].transactions[k] - tr.saveStatus = true - block.transactions.push(tr); - } - - } - if (block.transactions.length > 0) - { - bAdded++ - block.number = bAdded - block.status = "mined" - retBlocks.push(block) - } - - } - if (retBlocks.length === 0) - retBlocks.push(projectModel.stateListModel.createEmptyBlock()) - else - { - var last = retBlocks[retBlocks.length - 1] - last.number = -1 - last.status = "pending" - } - - model.blocks = retBlocks - blockModel.clear() - for (var j = 0; j < model.blocks.length; j++) - blockModel.append(model.blocks[j]) - - ensureNotFuturetime.start() - clientModel.setupScenario(model); - } - - Layout.preferredWidth: 100 - Layout.preferredHeight: 30 - buttonShortcut: "" - sourceImg: "qrc:/qml/img/recycleicon@2x.png" - Timer - { - id: reBuildNeeded - repeat: true - interval: 1000 - running: false - onTriggered: { - if (!parent.fillColor || parent.fillColor === "white") - parent.fillColor = "orange" - else - parent.fillColor = "white" - } - onRunningChanged: { - if (!running) - parent.fillColor = "white" - } - } - } - - ScenarioButton { - id: addTransaction - text: qsTr("Add Transaction") - onClicked: - { - var lastBlock = model.blocks[model.blocks.length - 1]; - console.log(lastBlock.status + "!!!") - if (lastBlock.status === "mined") - { - var newblock = projectModel.stateListModel.createEmptyBlock() - blockModel.appendBlock(newblock) - model.blocks.push(newblock); - } - - var item = TransactionHelper.defaultTransaction() - transactionDialog.stateAccounts = model.accounts - transactionDialog.execute = true - transactionDialog.open(model.blocks[model.blocks.length - 1].transactions.length, model.blocks.length - 1, item) - } - Layout.preferredWidth: 100 - Layout.preferredHeight: 30 - buttonShortcut: "" - sourceImg: "qrc:/qml/img/sendtransactionicon@2x.png" - } - - Timer - { - id: ensureNotFuturetime - interval: 1000 - repeat: false - running: false - } - - ScenarioButton { - id: addBlockBtn - text: qsTr("Add Block") - onClicked: - { - if (ensureNotFuturetime.running) - return - if (clientModel.mining || clientModel.running) - return - if (model.blocks.length > 0) - { - var lastBlock = model.blocks[model.blocks.length - 1] - if (lastBlock.status === "pending") - { - ensureNotFuturetime.start() - clientModel.mine() - } - else - addNewBlock() - } - else - addNewBlock() - - } - - function addNewBlock() - { - var block = projectModel.stateListModel.createEmptyBlock() - model.blocks.push(block) - blockModel.appendBlock(block) - } - Layout.preferredWidth: 100 - Layout.preferredHeight: 30 - buttonShortcut: "" - sourceImg: "qrc:/qml/img/addblock@2x.png" - } - - Connections - { - target: clientModel - onNewBlock: - { - console.log("new Block!!") - if (!clientModel.running) - { - var lastBlock = model.blocks[model.blocks.length - 1] - lastBlock.status = "mined" - lastBlock.number = model.blocks.length - var lastB = blockModel.get(model.blocks.length - 1) - lastB.status = "mined" - lastB.number = model.blocks.length - addBlockBtn.addNewBlock() - } - } - onStateCleared: - { - } - onNewRecord: - { - var blockIndex = parseInt(_r.transactionIndex.split(":")[0]) - 1 - var trIndex = parseInt(_r.transactionIndex.split(":")[1]) - if (blockIndex <= model.blocks.length - 1) - { - var item = model.blocks[blockIndex] - if (trIndex <= item.transactions.length - 1) - { - var tr = item.transactions[trIndex] - tr.returned = _r.returned - tr.recordIndex = _r.recordIndex - tr.logs = _r.logs - tr.sender = _r.sender - var trModel = blockModel.getTransaction(blockIndex, trIndex) - trModel.returned = _r.returned - trModel.recordIndex = _r.recordIndex - trModel.logs = _r.logs - trModel.sender = _r.sender - blockModel.setTransaction(blockIndex, trIndex, trModel) - return; - } - } - - // tr is not in the list. - var itemTr = TransactionHelper.defaultTransaction() - itemTr.saveStatus = false - itemTr.functionId = _r.function - itemTr.contractId = _r.contract - itemTr.gasAuto = true - itemTr.parameters = _r.parameters - itemTr.isContractCreation = itemTr.functionId === itemTr.contractId - itemTr.label = _r.label - itemTr.isFunctionCall = itemTr.functionId !== "" - itemTr.returned = _r.returned - itemTr.value = QEtherHelper.createEther(_r.value, QEther.Wei) - itemTr.sender = _r.sender - itemTr.recordIndex = _r.recordIndex - itemTr.logs = _r.logs - console.log(JSON.stringify(itemTr)) - model.blocks[model.blocks.length - 1].transactions.push(itemTr) - blockModel.appendTransaction(itemTr) - } - onMiningComplete: - { - } - } - - ScenarioButton { - id: newAccount - text: qsTr("New Account") - onClicked: { - model.accounts.push(projectModel.stateListModel.newAccount("1000000", QEther.Ether)) - } - Layout.preferredWidth: 100 - Layout.preferredHeight: 30 - buttonShortcut: "" - sourceImg: "qrc:/qml/img/newaccounticon@2x.png" - } - } - } - - TransactionDialog { - id: transactionDialog - property bool execute - onAccepted: { - var item = transactionDialog.getItem() - if (execute) - { - console.log("cc " + model.blocks.length) - var lastBlock = model.blocks[model.blocks.length - 1]; - console.log("mined?" + lastBlock.status) - if (lastBlock.status === "mined") - { - var newBlock = projectModel.stateListModel.createEmptyBlock(); - model.blocks.push(newBlock); - blockModel.appendBlock(newBlock) - } - if (!clientModel.running) - clientModel.executeTr(item) - } - else { - model.blocks[blockIndex].transactions[transactionIndex] = item - blockModel.setTransaction(blockIndex, transactionIndex, item) - chainChanged() - } - - } - } + id: blockChainPanel + property variant model + spacing: 0 + property int previousWidth + property variant debugTrRequested: [] + signal chainChanged + + onChainChanged: { + reBuildNeeded.start() + } + + onWidthChanged: + { + + if (width <= 630 || previousWidth <= 630) + { + fromWidth = 100 + toWidth = 100 + valueWidth = 200 + } + else + { + var diff = (width - previousWidth) / 3; + fromWidth = fromWidth + diff < 100 ? 100 : fromWidth + diff + toWidth = toWidth + diff < 100 ? 100 : toWidth + diff + valueWidth = valueWidth + diff < 200 ? 200 : valueWidth + diff + } + previousWidth = width + } + + function load(scenario) + { + if (!scenario) + return; + if (model) + chainChanged() + model = scenario + blockModel.clear() + for (var b in model.blocks) + blockModel.append(model.blocks[b]) + previousWidth = width + } + + property int statusWidth: 30 + property int fromWidth: 100 + property int toWidth: 100 + property int valueWidth: 200 + property int logsWidth: 50 + property int debugActionWidth: 50 + property int horizontalMargin: 10 + property int cellSpacing: 10 + + RowLayout + { + id: header + spacing: 0 + Layout.preferredHeight: 25 + Image { + id: debugImage + source: "qrc:/qml/img/recycleicon@2x.png" + Layout.preferredWidth: statusWidth + Layout.preferredHeight: 25 + fillMode: Image.PreserveAspectFit + } + Rectangle + { + Layout.preferredWidth: fromWidth + cellSpacing + Label + { + anchors.verticalCenter: parent.verticalCenter + text: "From" + anchors.left: parent.left + anchors.leftMargin: horizontalMargin + 5 + } + } + Label + { + text: "To" + Layout.preferredWidth: toWidth + cellSpacing + } + Label + { + text: "Value" + Layout.preferredWidth: valueWidth + cellSpacing + } + Label + { + text: "Logs" + Layout.preferredWidth: logsWidth + cellSpacing + } + Label + { + text: "" + Layout.preferredWidth: debugActionWidth + } + } + + Rectangle + { + Layout.preferredHeight: 500 + Layout.preferredWidth: parent.width + border.color: "#cccccc" + border.width: 2 + color: "white" + ScrollView + { + id: blockChainScrollView + anchors.fill: parent + anchors.topMargin: 10 + ColumnLayout + { + id: blockChainLayout + width: parent.width + spacing: 10 + Repeater // List of blocks + { + id: blockChainRepeater + model: blockModel + Block + { + scenario: blockChainPanel.model + Layout.preferredWidth: blockChainScrollView.width + Layout.preferredHeight: + { + return calculateHeight() + } + blockIndex: index + transactions: + { + if (index >= 0) + return blockModel.get(index).transactions + else + return [] + } + + status: + { + if (index >= 0) + return blockModel.get(index).status + else + return "" + } + + number: + { + if (index >= 0) + return blockModel.get(index).number + else + return 0 + } + } + } + } + } + } + + ListModel + { + id: blockModel + + function appendBlock(block) + { + blockModel.append(block); + } + + function appendTransaction(tr) + { + blockModel.get(blockModel.count - 1).transactions.append(tr) + } + + function removeTransaction(blockIndex, trIndex) + { + blockModel.get(blockIndex).transactions.remove(trIndex) + } + + function removeLastBlock() + { + blockModel.remove(blockModel.count - 1) + } + + function removeBlock(index) + { + blockModel.remove(index) + } + + function getTransaction(block, tr) + { + return blockModel.get(block).transactions.get(tr) + } + + function setTransaction(blockIndex, trIndex, tr) + { + blockModel.get(blockIndex).transactions.set(trIndex, tr) + } + + function setTransactionProperty(blockIndex, trIndex, propertyName, value) + { + blockModel.get(blockIndex).transactions.set(trIndex, { propertyName: value }) + } + } + + Rectangle + { + Layout.preferredWidth: parent.width + RowLayout + { + width: 4 * 100 + anchors.top: parent.top + anchors.topMargin: 10 + spacing: 0 + ScenarioButton { + id: rebuild + text: qsTr("Rebuild") + onClicked: + { + if (ensureNotFuturetime.running) + return; + reBuildNeeded.stop() + var retBlocks = []; + var bAdded = 0; + for (var j = 0; j < model.blocks.length; j++) + { + var b = model.blocks[j]; + var block = { + hash: b.hash, + number: b.number, + transactions: [], + status: b.status + } + for (var k = 0; k < model.blocks[j].transactions.length; k++) + { + if (blockModel.get(j).transactions.get(k).saveStatus) + { + var tr = model.blocks[j].transactions[k] + tr.saveStatus = true + block.transactions.push(tr); + } + + } + if (block.transactions.length > 0) + { + bAdded++ + block.number = bAdded + block.status = "mined" + retBlocks.push(block) + } + + } + if (retBlocks.length === 0) + retBlocks.push(projectModel.stateListModel.createEmptyBlock()) + else + { + var last = retBlocks[retBlocks.length - 1] + last.number = -1 + last.status = "pending" + } + + model.blocks = retBlocks + blockModel.clear() + for (var j = 0; j < model.blocks.length; j++) + blockModel.append(model.blocks[j]) + + ensureNotFuturetime.start() + clientModel.setupScenario(model); + } + + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/recycleicon@2x.png" + Timer + { + id: reBuildNeeded + repeat: true + interval: 1000 + running: false + onTriggered: { + if (!parent.fillColor || parent.fillColor === "white") + parent.fillColor = "orange" + else + parent.fillColor = "white" + } + onRunningChanged: { + if (!running) + parent.fillColor = "white" + } + } + } + + ScenarioButton { + id: addTransaction + text: qsTr("Add Transaction") + onClicked: + { + var lastBlock = model.blocks[model.blocks.length - 1]; + if (lastBlock.status === "mined") + { + var newblock = projectModel.stateListModel.createEmptyBlock() + blockModel.appendBlock(newblock) + model.blocks.push(newblock); + } + + var item = TransactionHelper.defaultTransaction() + transactionDialog.stateAccounts = model.accounts + transactionDialog.execute = true + transactionDialog.open(model.blocks[model.blocks.length - 1].transactions.length, model.blocks.length - 1, item) + } + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/sendtransactionicon@2x.png" + } + + Timer + { + id: ensureNotFuturetime + interval: 1000 + repeat: false + running: false + } + + ScenarioButton { + id: addBlockBtn + text: qsTr("Add Block") + onClicked: + { + if (ensureNotFuturetime.running) + return + if (clientModel.mining || clientModel.running) + return + if (model.blocks.length > 0) + { + var lastBlock = model.blocks[model.blocks.length - 1] + if (lastBlock.status === "pending") + { + ensureNotFuturetime.start() + clientModel.mine() + } + else + addNewBlock() + } + else + addNewBlock() + + } + + function addNewBlock() + { + var block = projectModel.stateListModel.createEmptyBlock() + model.blocks.push(block) + blockModel.appendBlock(block) + } + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/addblock@2x.png" + } + + Connections + { + target: clientModel + onNewBlock: + { + if (!clientModel.running) + { + var lastBlock = model.blocks[model.blocks.length - 1] + lastBlock.status = "mined" + lastBlock.number = model.blocks.length + var lastB = blockModel.get(model.blocks.length - 1) + lastB.status = "mined" + lastB.number = model.blocks.length + addBlockBtn.addNewBlock() + } + } + onStateCleared: + { + } + onNewRecord: + { + var blockIndex = parseInt(_r.transactionIndex.split(":")[0]) - 1 + var trIndex = parseInt(_r.transactionIndex.split(":")[1]) + if (blockIndex <= model.blocks.length - 1) + { + var item = model.blocks[blockIndex] + if (trIndex <= item.transactions.length - 1) + { + var tr = item.transactions[trIndex] + tr.returned = _r.returned + tr.recordIndex = _r.recordIndex + tr.logs = _r.logs + tr.sender = _r.sender + var trModel = blockModel.getTransaction(blockIndex, trIndex) + trModel.returned = _r.returned + trModel.recordIndex = _r.recordIndex + trModel.logs = _r.logs + trModel.sender = _r.sender + blockModel.setTransaction(blockIndex, trIndex, trModel) + return; + } + } + + // tr is not in the list. + var itemTr = TransactionHelper.defaultTransaction() + itemTr.saveStatus = false + itemTr.functionId = _r.function + itemTr.contractId = _r.contract + itemTr.gasAuto = true + itemTr.parameters = _r.parameters + itemTr.isContractCreation = itemTr.functionId === itemTr.contractId + itemTr.label = _r.label + itemTr.isFunctionCall = itemTr.functionId !== "" + itemTr.returned = _r.returned + itemTr.value = QEtherHelper.createEther(_r.value, QEther.Wei) + itemTr.sender = _r.sender + itemTr.recordIndex = _r.recordIndex + itemTr.logs = _r.logs + model.blocks[model.blocks.length - 1].transactions.push(itemTr) + blockModel.appendTransaction(itemTr) + } + onMiningComplete: + { + } + } + + ScenarioButton { + id: newAccount + text: qsTr("New Account") + onClicked: { + model.accounts.push(projectModel.stateListModel.newAccount("1000000", QEther.Ether)) + } + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/newaccounticon@2x.png" + } + } + } + + TransactionDialog { + id: transactionDialog + property bool execute + onAccepted: { + var item = transactionDialog.getItem() + if (execute) + { + var lastBlock = model.blocks[model.blocks.length - 1]; + if (lastBlock.status === "mined") + { + var newBlock = projectModel.stateListModel.createEmptyBlock(); + model.blocks.push(newBlock); + blockModel.appendBlock(newBlock) + } + if (!clientModel.running) + clientModel.executeTr(item) + } + else { + model.blocks[blockIndex].transactions[transactionIndex] = item + blockModel.setTransaction(blockIndex, transactionIndex, item) + chainChanged() + } + + } + } } diff --git a/mix/qml/Debugger.qml b/mix/qml/Debugger.qml index 3a0ed61a4..0129f864d 100644 --- a/mix/qml/Debugger.qml +++ b/mix/qml/Debugger.qml @@ -11,7 +11,7 @@ import "." Rectangle { id: debugPanel - property alias debugSlider: statesSlider + property alias debugSlider: statesSlider property alias solLocals: solLocals property alias solStorage: solStorage property alias solCallStack: solCallStack @@ -22,7 +22,7 @@ Rectangle { signal debugExecuteLocation(string documentId, var location) property string compilationErrorMessage property bool assemblyMode: false - signal panelClosed + signal panelClosed objectName: "debugPanel" color: "#ededed" clip: true @@ -39,10 +39,10 @@ Rectangle { machineStates.updateHeight(); } - function setTr(tr) - { - trName.text = tr.label - } + function setTr(tr) + { + trName.text = tr.label + } function displayCompilationErrorIfAny() { @@ -109,68 +109,68 @@ Rectangle { property alias solLocalsHeightSettings: solLocalsRect.height } - ColumnLayout { + ColumnLayout { id: debugScrollArea anchors.fill: parent - //orientation: Qt.Vertical - spacing: 0 - RowLayout - { - Layout.preferredWidth: parent.width - Layout.preferredHeight: 30 - Rectangle - { - Layout.preferredWidth: parent.width - Layout.preferredHeight: parent.height - color: "transparent" - Text { - anchors.centerIn: parent - text: qsTr("Current Transaction") - } - - Rectangle - { - anchors.left: parent.left - anchors.leftMargin: 10 - width: 30 - height: parent.height - color: "transparent" - anchors.verticalCenter: parent.verticalCenter - Image { - source: "qrc:/qml/img/leftarrow@2x.png" - width: parent.width - fillMode: Image.PreserveAspectFit - anchors.centerIn: parent - } - MouseArea - { - anchors.fill: parent - onClicked: - { - Debugger.init(null); - panelClosed() - } - } - } - } - } - - RowLayout - { - Layout.preferredWidth: parent.width - Layout.preferredHeight: 30 - Rectangle - { - Layout.preferredWidth: parent.width - Layout.preferredHeight: parent.height - color: "#2C79D3" - Text { - id: trName - color: "white" - anchors.centerIn: parent - } - } - } + //orientation: Qt.Vertical + spacing: 0 + RowLayout + { + Layout.preferredWidth: parent.width + Layout.preferredHeight: 30 + Rectangle + { + Layout.preferredWidth: parent.width + Layout.preferredHeight: parent.height + color: "transparent" + Text { + anchors.centerIn: parent + text: qsTr("Current Transaction") + } + + Rectangle + { + anchors.left: parent.left + anchors.leftMargin: 10 + width: 30 + height: parent.height + color: "transparent" + anchors.verticalCenter: parent.verticalCenter + Image { + source: "qrc:/qml/img/leftarrow@2x.png" + width: parent.width + fillMode: Image.PreserveAspectFit + anchors.centerIn: parent + } + MouseArea + { + anchors.fill: parent + onClicked: + { + Debugger.init(null); + panelClosed() + } + } + } + } + } + + RowLayout + { + Layout.preferredWidth: parent.width + Layout.preferredHeight: 30 + Rectangle + { + Layout.preferredWidth: parent.width + Layout.preferredHeight: parent.height + color: "#2C79D3" + Text { + id: trName + color: "white" + anchors.centerIn: parent + } + } + } ScrollView { @@ -520,12 +520,12 @@ Rectangle { } Rectangle { - id: separator - width: parent.width; - height: 1; - color: "#cccccc" - anchors.bottom: parent.bottom - } + id: separator + width: parent.width; + height: 1; + color: "#cccccc" + anchors.bottom: parent.bottom + } } } } diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index 22aa78f38..de19baf35 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -20,14 +20,14 @@ Rectangle { anchors.fill: parent id: root - property alias rightViewVisible: scenarioExe.visible + property alias rightViewVisible: scenarioExe.visible property alias webViewVisible: webPreview.visible property alias webView: webPreview property alias projectViewVisible: projectList.visible property alias projectNavigator: projectList property alias runOnProjectLoad: mainSettings.runOnProjectLoad - property alias rightPane: scenarioExe - property alias debuggerPanel: debugPanel + property alias rightPane: scenarioExe + property alias debuggerPanel: debugPanel property alias codeEditor: codeEditor property bool webViewHorizontal: codeWebSplitter.orientation === Qt.Vertical //vertical splitter positions elements vertically, splits screen horizontally property bool firstCompile: true @@ -43,17 +43,17 @@ Rectangle { } } - Connections { - target: debugPanel - onDebugExecuteLocation: { + Connections { + target: debugPanel + onDebugExecuteLocation: { codeEditor.highlightExecution(documentId, location); } - } + } Connections { target: codeEditor onBreakpointsChanged: { - debugPanel.setBreakpoints(codeEditor.getBreakpoints()); + debugPanel.setBreakpoints(codeEditor.getBreakpoints()); } } @@ -64,20 +64,20 @@ Rectangle { } function toggleRightView() { - scenarioExe.visible = !scenarioExe.visible; + scenarioExe.visible = !scenarioExe.visible; } function ensureRightView() { - scenarioExe.visible = true; + scenarioExe.visible = true; } function rightViewIsVisible() { - return scenarioExe.visible; + return scenarioExe.visible; } function hideRightView() { - scenarioExe.visible = lfalse; + scenarioExe.visible = lfalse; } function toggleWebPreview() { @@ -99,8 +99,8 @@ Rectangle { function displayCompilationErrorIfAny() { - scenarioExe.visible = true; - scenarioExe.displayCompilationErrorIfAny(); + scenarioExe.visible = true; + scenarioExe.displayCompilationErrorIfAny(); } Settings { @@ -154,7 +154,7 @@ Rectangle { id: splitSettings property alias projectWidth: projectList.width property alias contentViewWidth: contentView.width - property alias rightViewWidth: scenarioExe.width + property alias rightViewWidth: scenarioExe.width } Splitter @@ -199,45 +199,45 @@ Rectangle { } } - ScenarioExecution - { - id: scenarioExe; - visible: false; - Layout.fillHeight: true - Keys.onEscapePressed: visible = false - Layout.minimumWidth: 650 - anchors.right: parent.right - } - - Debugger - { - id: debugPanel - visible: false - Layout.fillHeight: true - Keys.onEscapePressed: visible = false - Layout.minimumWidth: 650 - anchors.right: parent.right - } - - Connections { - target: clientModel - onDebugDataReady: { - scenarioExe.visible = false - debugPanel.visible = true - if (scenarioExe.bc.debugTrRequested) - { - debugPanel.setTr(scenarioExe.bc.model.blocks[scenarioExe.bc.debugTrRequested[0]].transactions[scenarioExe.bc.debugTrRequested[1]]) - } - } - } - - Connections { - target: debugPanel - onPanelClosed: { - debugPanel.visible = false - scenarioExe.visible = true - } - } + ScenarioExecution + { + id: scenarioExe; + visible: false; + Layout.fillHeight: true + Keys.onEscapePressed: visible = false + Layout.minimumWidth: 650 + anchors.right: parent.right + } + + Debugger + { + id: debugPanel + visible: false + Layout.fillHeight: true + Keys.onEscapePressed: visible = false + Layout.minimumWidth: 650 + anchors.right: parent.right + } + + Connections { + target: clientModel + onDebugDataReady: { + scenarioExe.visible = false + debugPanel.visible = true + if (scenarioExe.bc.debugTrRequested) + { + debugPanel.setTr(scenarioExe.bc.model.blocks[scenarioExe.bc.debugTrRequested[0]].transactions[scenarioExe.bc.debugTrRequested[1]]) + } + } + } + + Connections { + target: debugPanel + onPanelClosed: { + debugPanel.visible = false + scenarioExe.visible = true + } + } } } } diff --git a/mix/qml/QAddressView.qml b/mix/qml/QAddressView.qml index 3c34d45eb..4781d092b 100644 --- a/mix/qml/QAddressView.qml +++ b/mix/qml/QAddressView.qml @@ -39,9 +39,6 @@ Item { accountRef.clear(); accountRef.append({"itemid": " - "}); - - console.log(blockIndex) - console.log(transactionIndex) if (subType === "contract" || subType === "address") { var trCr = 0; diff --git a/mix/qml/ScenarioButton.qml b/mix/qml/ScenarioButton.qml index dbe6dd13a..4dd7bc53f 100644 --- a/mix/qml/ScenarioButton.qml +++ b/mix/qml/ScenarioButton.qml @@ -4,64 +4,64 @@ import QtQuick.Layouts 1.0 import QtQuick.Controls.Styles 1.1 Rectangle { - id: buttonActionContainer - property string text - property string buttonShortcut - property string sourceImg - property string fillColor - signal clicked + id: buttonActionContainer + property string text + property string buttonShortcut + property string sourceImg + property string fillColor + signal clicked - Rectangle { - id: contentRectangle - anchors.fill: parent - border.color: "#cccccc" - border.width: 1 - radius: 4 - color: parent.fillColor ? parent.fillColor : "white" - Image { - id: debugImage - anchors { - left: parent.left - right: parent.right - top: parent.top - bottom: parent.bottom - bottomMargin: debugImg.pressed ? 0 : 2; - topMargin: debugImg.pressed ? 2 : 0; - } - source: sourceImg - fillMode: Image.PreserveAspectFit - height: 30 - } + Rectangle { + id: contentRectangle + anchors.fill: parent + border.color: "#cccccc" + border.width: 1 + radius: 4 + color: parent.fillColor ? parent.fillColor : "white" + Image { + id: debugImage + anchors { + left: parent.left + right: parent.right + top: parent.top + bottom: parent.bottom + bottomMargin: debugImg.pressed ? 0 : 2; + topMargin: debugImg.pressed ? 2 : 0; + } + source: sourceImg + fillMode: Image.PreserveAspectFit + height: 30 + } - Button { - anchors.fill: parent - id: debugImg - action: buttonAction - style: ButtonStyle { - background: Rectangle { - color: "transparent" - } - } - } + Button { + anchors.fill: parent + id: debugImg + action: buttonAction + style: ButtonStyle { + background: Rectangle { + color: "transparent" + } + } + } - Action { - id: buttonAction - shortcut: buttonShortcut - onTriggered: { - buttonActionContainer.clicked(); - } - } - } + Action { + id: buttonAction + shortcut: buttonShortcut + onTriggered: { + buttonActionContainer.clicked(); + } + } + } - Rectangle - { - anchors.top: contentRectangle.bottom - anchors.topMargin: 15 - width: parent.width - Text - { - text: buttonActionContainer.text - anchors.centerIn: parent - } - } + Rectangle + { + anchors.top: contentRectangle.bottom + anchors.topMargin: 15 + width: parent.width + Text + { + text: buttonActionContainer.text + anchors.centerIn: parent + } + } } diff --git a/mix/qml/ScenarioExecution.qml b/mix/qml/ScenarioExecution.qml index a5053e4d7..bc872bff7 100644 --- a/mix/qml/ScenarioExecution.qml +++ b/mix/qml/ScenarioExecution.qml @@ -9,49 +9,49 @@ import "js/ErrorLocationFormater.js" as ErrorLocationFormater import "." Rectangle { - color: "#ededed" - property alias bc: blockChain + color: "#ededed" + property alias bc: blockChain - Connections - { - target: projectModel - onProjectLoaded: { - loader.init() - } + Connections + { + target: projectModel + onProjectLoaded: { + loader.init() + } - } + } - Column - { - anchors.margins: 10 - anchors.fill: parent - spacing: 10 - ScenarioLoader - { - height: 70 - width: parent.width - id: loader - } + Column + { + anchors.margins: 10 + anchors.fill: parent + spacing: 10 + ScenarioLoader + { + height: 70 + width: parent.width + id: loader + } - Rectangle - { - width: parent.width - height: 1 - color: "#cccccc" - } + Rectangle + { + width: parent.width + height: 1 + color: "#cccccc" + } - Connections - { - target: loader - onLoaded: { - blockChain.load(scenario) - } - } + Connections + { + target: loader + onLoaded: { + blockChain.load(scenario) + } + } - BlockChain - { - id: blockChain - width: parent.width - } - } + BlockChain + { + id: blockChain + width: parent.width + } + } } diff --git a/mix/qml/ScenarioLoader.qml b/mix/qml/ScenarioLoader.qml index 50e958a5c..93f4f059b 100644 --- a/mix/qml/ScenarioLoader.qml +++ b/mix/qml/ScenarioLoader.qml @@ -12,164 +12,164 @@ import "." RowLayout { - signal restored(variant scenario) - signal saved(variant scenario) - signal duplicated(variant scenario) - signal loaded(variant scenario) - spacing: 0 - function init() - { - scenarioList.load() - } - - id: blockChainSelector - - Dialog { - id: newStateWin - modality: Qt.ApplicationModal - title: qsTr("New Project"); - - width: 320 - height: 120 - - visible: false - - contentItem: Rectangle { - anchors.fill: parent - anchors.margins: 10 - RowLayout { - anchors.verticalCenter: parent.verticalCenter - Text { - text: qsTr("Name:") - } - - Rectangle - { - Layout.preferredWidth: 250 - Layout.preferredHeight: parent.height - border.width: 1 - border.color: "#cccccc" - TextInput - { - anchors.fill: parent - id: stateName - } - } - } - RowLayout - { - anchors.bottom: parent.bottom - anchors.right: parent.right; - function acceptAndClose() - { - var item = projectModel.stateListModel.createDefaultState(); - item.title = stateName.text - projectModel.stateListModel.appendState(item) - projectModel.stateListModel.save() - close() - scenarioList.currentIndex = projectModel.stateListModel.count - 1 - } - - function close() - { - newStateWin.close() - stateName.text = "" - } - - Button { - id: okButton; - enabled: stateName.text !== "" - text: qsTr("OK"); - onClicked: { - parent.acceptAndClose(); - } - } - Button { - text: qsTr("Cancel"); - onClicked: parent.close(); - } - } - } - } - - ComboBox - { - id: scenarioList - model: projectModel.stateListModel - textRole: "title" - onCurrentIndexChanged: - { - restoreScenario.restore() - } - - function load() - { - var state = projectModel.stateListModel.getState(currentIndex) - loaded(state) - } - } - - Row - { - Layout.preferredWidth: 100 * 4 - Layout.preferredHeight: 30 - spacing: 0 - ScenarioButton { - id: restoreScenario - width: 100 - height: 30 - buttonShortcut: "" - sourceImg: "qrc:/qml/img/restoreicon@2x.png" - onClicked: { - restore() - } - text: qsTr("Restore") - function restore() - { - var state = projectModel.stateListModel.reloadStateFromFromProject(scenarioList.currentIndex) - restored(state) - loaded(state) - } - } - - ScenarioButton { - id: saveScenario - text: qsTr("Save") - onClicked: { - projectModel.saveProjectFile() - saved(state) - } - width: 100 - height: 30 - buttonShortcut: "" - sourceImg: "qrc:/qml/img/saveicon@2x.png" - } - - ScenarioButton - { - id: duplicateScenario - text: qsTr("Duplicate") - onClicked: { - projectModel.stateListModel.duplicateState(scenarioList.currentIndex) - duplicated(state) - } - width: 100 - height: 30 - buttonShortcut: "" - sourceImg: "qrc:/qml/img/duplicateicon@2x.png" - } - - ScenarioButton { - id: addScenario - width: 100 - height: 30 - buttonShortcut: "" - sourceImg: "qrc:/qml/img/plus.png" - onClicked: { - newStateWin.open() - } - text: qsTr("New") - } - } + signal restored(variant scenario) + signal saved(variant scenario) + signal duplicated(variant scenario) + signal loaded(variant scenario) + spacing: 0 + function init() + { + scenarioList.load() + } + + id: blockChainSelector + + Dialog { + id: newStateWin + modality: Qt.ApplicationModal + title: qsTr("New Project"); + + width: 320 + height: 120 + + visible: false + + contentItem: Rectangle { + anchors.fill: parent + anchors.margins: 10 + RowLayout { + anchors.verticalCenter: parent.verticalCenter + Text { + text: qsTr("Name:") + } + + Rectangle + { + Layout.preferredWidth: 250 + Layout.preferredHeight: parent.height + border.width: 1 + border.color: "#cccccc" + TextInput + { + anchors.fill: parent + id: stateName + } + } + } + RowLayout + { + anchors.bottom: parent.bottom + anchors.right: parent.right; + function acceptAndClose() + { + var item = projectModel.stateListModel.createDefaultState(); + item.title = stateName.text + projectModel.stateListModel.appendState(item) + projectModel.stateListModel.save() + close() + scenarioList.currentIndex = projectModel.stateListModel.count - 1 + } + + function close() + { + newStateWin.close() + stateName.text = "" + } + + Button { + id: okButton; + enabled: stateName.text !== "" + text: qsTr("OK"); + onClicked: { + parent.acceptAndClose(); + } + } + Button { + text: qsTr("Cancel"); + onClicked: parent.close(); + } + } + } + } + + ComboBox + { + id: scenarioList + model: projectModel.stateListModel + textRole: "title" + onCurrentIndexChanged: + { + restoreScenario.restore() + } + + function load() + { + var state = projectModel.stateListModel.getState(currentIndex) + loaded(state) + } + } + + Row + { + Layout.preferredWidth: 100 * 4 + Layout.preferredHeight: 30 + spacing: 0 + ScenarioButton { + id: restoreScenario + width: 100 + height: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/restoreicon@2x.png" + onClicked: { + restore() + } + text: qsTr("Restore") + function restore() + { + var state = projectModel.stateListModel.reloadStateFromFromProject(scenarioList.currentIndex) + restored(state) + loaded(state) + } + } + + ScenarioButton { + id: saveScenario + text: qsTr("Save") + onClicked: { + projectModel.saveProjectFile() + saved(state) + } + width: 100 + height: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/saveicon@2x.png" + } + + ScenarioButton + { + id: duplicateScenario + text: qsTr("Duplicate") + onClicked: { + projectModel.stateListModel.duplicateState(scenarioList.currentIndex) + duplicated(state) + } + width: 100 + height: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/duplicateicon@2x.png" + } + + ScenarioButton { + id: addScenario + width: 100 + height: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/plus.png" + onClicked: { + newStateWin.open() + } + text: qsTr("New") + } + } } diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index f056acc22..992113cc6 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -16,32 +16,33 @@ Item { property string defaultAccount: "cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074" //support for old project function fromPlainStateItem(s) { - if (!s.accounts) + if (!s.accounts) s.accounts = [stateListModel.newAccount("1000000", QEther.Ether, defaultAccount)]; //support for old project if (!s.contracts) s.contracts = []; - var ret = {}; - ret.title = s.title; - ret.transactions = s.transactions.filter(function(t) { return !t.stdContract; }).map(fromPlainTransactionItem); //support old projects by filtering std contracts - if (s.blocks) - ret.blocks = s.blocks.map(fromPlainBlockItem); - ret.accounts = s.accounts.map(fromPlainAccountItem); - ret.contracts = s.contracts.map(fromPlainAccountItem); - ret.miner = s.miner; - - // support old projects - if (!ret.blocks) - { - ret.blocks = [{ - hash: "", - number: -1, - transactions: [], - status: "pending" - }] - for (var j in ret.transactions) - ret.blocks[0].transactions.push(fromPlainTransactionItem(toPlainTransactionItem(ret.transactions[j]))) - } + var ret = {}; + ret.title = s.title; + ret.transactions = s.transactions.filter(function(t) { return !t.stdContract; }).map(fromPlainTransactionItem); //support old projects by filtering std contracts + if (s.blocks) + ret.blocks = s.blocks.map(fromPlainBlockItem); + ret.accounts = s.accounts.map(fromPlainAccountItem); + ret.contracts = s.contracts.map(fromPlainAccountItem); + ret.miner = s.miner; + + // support old projects + if (!ret.blocks) + { + ret.blocks = [{ + hash: "", + number: -1, + transactions: [], + status: "pending" + }] + for (var j in ret.transactions) + ret.blocks[0].transactions.push(fromPlainTransactionItem(toPlainTransactionItem(ret.transactions[j]))) + } + return ret; } function fromPlainAccountItem(t) @@ -73,12 +74,12 @@ Item { sender: t.sender, isContractCreation: t.isContractCreation, label: t.label, - isFunctionCall: t.isFunctionCall, - saveStatus: t.saveStatus + isFunctionCall: t.isFunctionCall, + saveStatus: t.saveStatus }; - if (r.saveStatus === undefined) - r.saveStatus = true + if (r.saveStatus === undefined) + r.saveStatus = true if (r.isFunctionCall === undefined) r.isFunctionCall = true; @@ -95,22 +96,22 @@ Item { return r; } - function fromPlainBlockItem(b) - { - var r = { - hash: b.hash, - number: b.number, - transactions: b.transactions.filter(function(t) { return !t.stdContract; }).map(fromPlainTransactionItem), //support old projects by filtering std contracts - status: b.status - } - return r; - } + function fromPlainBlockItem(b) + { + var r = { + hash: b.hash, + number: b.number, + transactions: b.transactions.filter(function(t) { return !t.stdContract; }).map(fromPlainTransactionItem), //support old projects by filtering std contracts + status: b.status + } + return r; + } function toPlainStateItem(s) { return { title: s.title, - blocks: s.blocks.map(toPlainBlockItem), - transactions: s.transactions.map(toPlainTransactionItem), + blocks: s.blocks.map(toPlainBlockItem), + transactions: s.transactions.map(toPlainTransactionItem), accounts: s.accounts.map(toPlainAccountItem), contracts: s.contracts.map(toPlainAccountItem), miner: s.miner @@ -127,16 +128,16 @@ Item { return ''; } - function toPlainBlockItem(b) - { - var r = { - hash: b.hash, - number: b.number, - transactions: b.transactions.map(toPlainTransactionItem), - status: b.status - } - return r; - } + function toPlainBlockItem(b) + { + var r = { + hash: b.hash, + number: b.number, + transactions: b.transactions.map(toPlainTransactionItem), + status: b.status + } + return r; + } function toPlainAccountItem(t) { @@ -167,8 +168,8 @@ Item { parameters: {}, isContractCreation: t.isContractCreation, label: t.label, - isFunctionCall: t.isFunctionCall, - saveStatus: t.saveStatus + isFunctionCall: t.isFunctionCall, + saveStatus: t.saveStatus }; for (var key in t.parameters) r.parameters[key] = t.parameters[key]; @@ -189,16 +190,16 @@ Item { projectData.states.push(toPlainStateItem(stateList[i])); } projectData.defaultStateIndex = stateListModel.defaultStateIndex; - stateListModel.data = projectData + stateListModel.data = projectData - } + } onNewProject: { var state = toPlainStateItem(stateListModel.createDefaultState()); state.title = qsTr("Default"); projectData.states = [ state ]; projectData.defaultStateIndex = 0; - stateListModel.loadStatesFromProject(projectData); - } + stateListModel.loadStatesFromProject(projectData); + } } Connections { @@ -215,40 +216,40 @@ Item { id: stateDialog onAccepted: { var item = stateDialog.getItem(); - saveState(item); + saveState(item); } - function saveState(item) - { - if (stateDialog.stateIndex < stateListModel.count) { - if (stateDialog.isDefault) - stateListModel.defaultStateIndex = stateIndex; - stateList[stateDialog.stateIndex] = item; - stateListModel.set(stateDialog.stateIndex, item); - } else { - if (stateDialog.isDefault) - stateListModel.defaultStateIndex = 0; - stateList.push(item); - stateListModel.append(item); - } - if (stateDialog.isDefault) - stateListModel.defaultStateChanged(); - stateListModel.save(); - } + function saveState(item) + { + if (stateDialog.stateIndex < stateListModel.count) { + if (stateDialog.isDefault) + stateListModel.defaultStateIndex = stateIndex; + stateList[stateDialog.stateIndex] = item; + stateListModel.set(stateDialog.stateIndex, item); + } else { + if (stateDialog.isDefault) + stateListModel.defaultStateIndex = 0; + stateList.push(item); + stateListModel.append(item); + } + if (stateDialog.isDefault) + stateListModel.defaultStateChanged(); + stateListModel.save(); + } } ListModel { id: stateListModel property int defaultStateIndex: 0 - property variant data - signal defaultStateChanged; + property variant data + signal defaultStateChanged; signal stateListModelReady; signal stateRun(int index) signal stateDeleted(int index) function defaultTransactionItem() { return TransactionHelper.defaultTransaction(); - } + } function newAccount(_balance, _unit, _secret) { @@ -259,35 +260,35 @@ Item { return { name: name, secret: _secret, balance: QEtherHelper.createEther(_balance, _unit), address: address }; } - function duplicateState(index) - { - var state = stateList[index] - var item = fromPlainStateItem(toPlainStateItem(state)) - item.title = qsTr("Copy of") + " " + state.title - appendState(item) - save() - } - - function createEmptyBlock() - { - return { - hash: "", - number: -1, - transactions: [], - status: "pending" - } - } + function duplicateState(index) + { + var state = stateList[index] + var item = fromPlainStateItem(toPlainStateItem(state)) + item.title = qsTr("Copy of") + " " + state.title + appendState(item) + save() + } + + function createEmptyBlock() + { + return { + hash: "", + number: -1, + transactions: [], + status: "pending" + } + } function createDefaultState() { var item = { title: "", transactions: [], accounts: [], - contracts: [], - blocks: [{ status: "pending", number: -1, hash: "", transactions: []}] - }; + contracts: [], + blocks: [{ status: "pending", number: -1, hash: "", transactions: []}] + }; - var account = newAccount("1000000", QEther.Ether, defaultAccount) + var account = newAccount("1000000", QEther.Ether, defaultAccount) item.accounts.push(account); item.miner = account; @@ -299,8 +300,8 @@ Item { ctorTr.label = qsTr("Deploy") + " " + ctorTr.contractId; ctorTr.sender = item.accounts[0].secret; item.transactions.push(ctorTr); - item.blocks[0].transactions.push(ctorTr) - } + item.blocks[0].transactions.push(ctorTr) + } return item; } @@ -356,19 +357,19 @@ Item { stateDialog.open(stateListModel.count, item, false); } - function appendState(item) - { - stateListModel.append(item); - stateList.push(item); - } + function appendState(item) + { + stateListModel.append(item); + stateList.push(item); + } function editState(index) { stateDialog.open(index, stateList[index], defaultStateIndex === index); } - function getState(index) { - return stateList[index]; - } + function getState(index) { + return stateList[index]; + } function debugDefaultState() { if (defaultStateIndex >= 0 && defaultStateIndex < stateList.length) @@ -377,8 +378,8 @@ Item { function runState(index) { var item = stateList[index]; - //clientModel.setupState(item); - //stateRun(index); + clientModel.setupScenario(item); + stateRun(index); } function deleteState(index) { @@ -404,20 +405,20 @@ Item { return stateList[defaultStateIndex].title; } - function reloadStateFromFromProject(index) - { - if (data) - { - var item = fromPlainStateItem(data.states[index]) - stateListModel.set(index, item) - stateList[index] = item - return item - } - } + function reloadStateFromFromProject(index) + { + if (data) + { + var item = fromPlainStateItem(data.states[index]) + stateListModel.set(index, item) + stateList[index] = item + return item + } + } function loadStatesFromProject(projectData) { - data = projectData + data = projectData if (!projectData.states) projectData.states = []; if (projectData.defaultStateIndex !== undefined) diff --git a/mix/qml/StructView.qml b/mix/qml/StructView.qml index 9cb461204..880f22057 100644 --- a/mix/qml/StructView.qml +++ b/mix/qml/StructView.qml @@ -9,7 +9,7 @@ Column property alias members: repeater.model //js array property variant accounts property var value: ({}) - property int blockIndex + property int blockIndex property int transactionIndex property string context Layout.fillWidth: true diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index 56810b375..287ba08c2 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -17,7 +17,7 @@ Dialog { visible: false title: qsTr("Edit Transaction") property int transactionIndex - property int blockIndex + property int blockIndex property alias gas: gasValueEdit.gasValue; property alias gasAuto: gasAutoCheck.checked; property alias gasPrice: gasPriceField.value; @@ -28,24 +28,24 @@ Dialog { property var paramsModel: []; property bool useTransactionDefaultValue: false property alias stateAccounts: senderComboBox.model - property bool saveStatus + property bool saveStatus signal accepted; StateDialogStyle { id: transactionDialogStyle } - function open(index, blockIdx, item) { + function open(index, blockIdx, item) { rowFunction.visible = !useTransactionDefaultValue; rowValue.visible = !useTransactionDefaultValue; rowGas.visible = !useTransactionDefaultValue; rowGasPrice.visible = !useTransactionDefaultValue; - transactionIndex = index - blockIndex = blockIdx - typeLoader.transactionIndex = index - typeLoader.blockIndex = blockIdx - saveStatus = item.saveStatus + transactionIndex = index + blockIndex = blockIdx + typeLoader.transactionIndex = index + typeLoader.blockIndex = blockIdx + saveStatus = item.saveStatus gasValueEdit.gasValue = item.gas; gasAutoCheck.checked = item.gasAuto ? true : false; gasPriceField.value = item.gasPrice; @@ -64,7 +64,7 @@ Dialog { for (var c in contracts) { contractsModel.append({ cid: c, text: contracts[c].contract.name }); if (contracts[c].contract.name === contractId) - contractIndex = contractsModel.count - 1; + contractIndex = contractsModel.count - 1; } if (contractIndex == -1 && contractsModel.count > 0) @@ -233,7 +233,7 @@ Dialog { item.functionId = item.contractId; item.label = qsTr("Deploy") + " " + item.contractId; } - item.saveStatus = saveStatus + item.saveStatus = saveStatus item.sender = senderComboBox.model[senderComboBox.currentIndex].secret; item.parameters = paramValues; return item; diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 1e6169e5d..31f30e2da 100644 --- a/mix/qml/js/ProjectModel.js +++ b/mix/qml/js/ProjectModel.js @@ -82,9 +82,9 @@ function saveProjectFile() }; for (var i = 0; i < projectListModel.count; i++) projectData.files.push({ - title: projectListModel.get(i).name, - fileName: projectListModel.get(i).fileName, - }); + title: projectListModel.get(i).name, + fileName: projectListModel.get(i).fileName, + }); projectFileSaving(projectData); var json = JSON.stringify(projectData, null, "\t"); @@ -98,52 +98,52 @@ function saveProjectFile() function loadProject(path) { closeProject(function() { - console.log("Loading project at " + path); - var projectFile = path + projectFileName; - var json = fileIo.readFile(projectFile); - if (!json) - return; - var projectData = JSON.parse(json); - if (projectData.deploymentDir) - projectModel.deploymentDir = projectData.deploymentDir - if (projectData.packageHash) - deploymentDialog.packageHash = projectData.packageHash - if (projectData.packageBase64) - deploymentDialog.packageBase64 = projectData.packageBase64 - if (projectData.applicationUrlEth) - deploymentDialog.applicationUrlEth = projectData.applicationUrlEth - if (projectData.applicationUrlHttp) - deploymentDialog.applicationUrlHttp = projectData.applicationUrlHttp - if (!projectData.title) { - var parts = path.split("/"); - projectData.title = parts[parts.length - 2]; - } - deploymentAddresses = projectData.deploymentAddresses ? projectData.deploymentAddresses : []; - projectTitle = projectData.title; - projectPath = path; - if (!projectData.files) - projectData.files = []; - - for(var i = 0; i < projectData.files.length; i++) { - var entry = projectData.files[i]; - if (typeof(entry) === "string") - addFile(entry); //TODO: remove old project file support - else - addFile(entry.fileName, entry.title); - } - if (mainApplication.trackLastProject) - projectSettings.lastProjectPath = path; - projectLoading(projectData); - projectLoaded() - - //TODO: move this to codemodel - var contractSources = {}; - for (var d = 0; d < listModel.count; d++) { - var doc = listModel.get(d); - if (doc.isContract) - contractSources[doc.documentId] = fileIo.readFile(doc.path); - } - codeModel.reset(contractSources); + console.log("Loading project at " + path); + var projectFile = path + projectFileName; + var json = fileIo.readFile(projectFile); + if (!json) + return; + var projectData = JSON.parse(json); + if (projectData.deploymentDir) + projectModel.deploymentDir = projectData.deploymentDir + if (projectData.packageHash) + deploymentDialog.packageHash = projectData.packageHash + if (projectData.packageBase64) + deploymentDialog.packageBase64 = projectData.packageBase64 + if (projectData.applicationUrlEth) + deploymentDialog.applicationUrlEth = projectData.applicationUrlEth + if (projectData.applicationUrlHttp) + deploymentDialog.applicationUrlHttp = projectData.applicationUrlHttp + if (!projectData.title) { + var parts = path.split("/"); + projectData.title = parts[parts.length - 2]; + } + deploymentAddresses = projectData.deploymentAddresses ? projectData.deploymentAddresses : []; + projectTitle = projectData.title; + projectPath = path; + if (!projectData.files) + projectData.files = []; + + for(var i = 0; i < projectData.files.length; i++) { + var entry = projectData.files[i]; + if (typeof(entry) === "string") + addFile(entry); //TODO: remove old project file support + else + addFile(entry.fileName, entry.title); + } + if (mainApplication.trackLastProject) + projectSettings.lastProjectPath = path; + projectLoading(projectData); + projectLoaded() + + //TODO: move this to codemodel + var contractSources = {}; + for (var d = 0; d < listModel.count; d++) { + var doc = listModel.get(d); + if (doc.isContract) + contractSources[doc.documentId] = fileIo.readFile(doc.path); + } + codeModel.reset(contractSources); }); } @@ -162,12 +162,12 @@ function addFile(fileName, title) { path: p, fileName: fileName, name: title !== undefined ? title : fileName, - documentId: fileName, - syntaxMode: syntaxMode, - isText: isContract || isHtml || isCss || isJs, - isContract: isContract, - isHtml: isHtml, - groupName: groupName + documentId: fileName, + syntaxMode: syntaxMode, + isText: isContract || isHtml || isCss || isJs, + isContract: isContract, + isHtml: isHtml, + groupName: groupName }; projectListModel.append(docData); diff --git a/mix/qml/js/TransactionHelper.js b/mix/qml/js/TransactionHelper.js index 8a7c5f5b8..f8bad03ed 100644 --- a/mix/qml/js/TransactionHelper.js +++ b/mix/qml/js/TransactionHelper.js @@ -12,8 +12,8 @@ function defaultTransaction() stdContract: false, isContractCreation: true, label: "", - isFunctionCall: true, - saveStatus: true + isFunctionCall: true, + saveStatus: true }; } From cb380d66bbbee9f5f92e9a6c1393b4db4cf3fc89 Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 10 Jun 2015 14:34:24 +0200 Subject: [PATCH 12/40] - allow ignore nonce checking --- libethereum/BlockChain.cpp | 10 +++++++--- libethereum/BlockChain.h | 2 +- mix/MixClient.cpp | 4 ++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 479524f89..1d53e73f9 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -357,7 +357,7 @@ pair BlockChain::attemptImport(bytes const& _block, O { try { - return make_pair(ImportResult::Success, import(verifyBlock(_block, m_onBad), _stateDB, _ir)); + return make_pair(ImportResult::Success, import(verifyBlock(_block, m_onBad, _ir), _stateDB, _ir)); } catch (UnknownParent&) { @@ -1063,12 +1063,16 @@ bytes BlockChain::block(h256 const& _hash) const return m_blocks[_hash]; } -VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function const& _onBad) +VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function const& _onBad, ImportRequirements::value _ir) { VerifiedBlockRef res; try { - res.info.populate(_block, CheckEverything); + Strictness strictNess = Strictness::CheckEverything; + if (_ir & ~ImportRequirements::ValidNonce) + strictNess = Strictness::IgnoreNonce; + + res.info.populate(_block, strictNess); res.info.verifyInternals(&_block); } catch (Exception& ex) diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 4934d4f2a..1aa15b856 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -258,7 +258,7 @@ public: void garbageCollect(bool _force = false); /// Verify block and prepare it for enactment - static VerifiedBlockRef verifyBlock(bytes const& _block, std::function const& _onBad = std::function()); + static VerifiedBlockRef verifyBlock(bytes const& _block, std::function const& _onBad = std::function(), ImportRequirements::value _ir = ImportRequirements::Default); /// Change the function that is called with a bad block. template void setOnBad(T const& _t) { m_onBad = _t; } diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index 31b4772b4..df3795c7e 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -73,6 +73,10 @@ MixClient::MixClient(std::string const& _dbPath): resetState(std::unordered_map()); } +MixClient::~MixClient() +{ +} + void MixClient::resetState(std::unordered_map const& _accounts, Secret const& _miner) { From cf4c191a98d3950fe61daa9764cbbf09805498b0 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 11 Jun 2015 12:27:39 +0200 Subject: [PATCH 13/40] CLMiner, query only GPU devices By default now, CPU is not considered an OpenCL device. Also added a new argument --allow-opencl-cpu, that would allow OpenCL to include CPU devices if the user's openCL implementation caters for it. --- ethminer/MinerAux.h | 2 ++ libethash-cl/ethash_cl_miner.cpp | 36 ++++++++++++++++++-------- libethash-cl/ethash_cl_miner.h | 5 ++++ libethash-cl/ethash_cl_miner_kernel.cl | 4 +-- libethcore/Ethash.cpp | 5 ++++ libethcore/Ethash.h | 2 ++ 6 files changed, 40 insertions(+), 14 deletions(-) diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 476c810c2..aac68f1a7 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -132,6 +132,8 @@ public: ProofOfWork::GPUMiner::listDevices(); exit(0); } + else if (arg == "--allow-opencl-cpu") + ProofOfWork::GPUMiner::allowCPU(); else if (arg == "--phone-home" && i + 1 < argc) { string m = argv[++i]; diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 1a5eaddc3..054985a38 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -51,6 +51,8 @@ using namespace std; // TODO: If at any point we can use libdevcore in here then we should switch to using a LogChannel #define ETHCL_LOG(_contents) cout << "[OPENCL]:" << _contents << endl +// Types of OpenCL devices we are interested in +#define ETHCL_QUERIED_DEVICE_TYPES (CL_DEVICE_TYPE_GPU | CL_DEVICE_TYPE_ACCELERATOR) static void addDefinition(string& _source, char const* _id, unsigned _value) { @@ -82,9 +84,8 @@ string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _deviceId) } // get GPU device of the selected platform - vector devices; unsigned platform_num = min(_platformId, platforms.size() - 1); - platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); + vector devices = getDevices(platforms, _platformId); if (devices.empty()) { ETHCL_LOG("No OpenCL devices found."); @@ -99,6 +100,17 @@ string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _deviceId) return "{ \"platform\": \"" + platforms[platform_num].getInfo() + "\", \"device\": \"" + device.getInfo() + "\", \"version\": \"" + device_version + "\" }"; } +std::vector ethash_cl_miner::getDevices(std::vector const& _platforms, unsigned _platformId) +{ + vector devices; + unsigned platform_num = min(_platformId, _platforms.size() - 1); + _platforms[platform_num].getDevices( + s_allowCPU ? CL_DEVICE_TYPE_ALL : ETHCL_QUERIED_DEVICE_TYPES, + &devices + ); + return devices; +} + unsigned ethash_cl_miner::getNumPlatforms() { vector platforms; @@ -116,9 +128,7 @@ unsigned ethash_cl_miner::getNumDevices(unsigned _platformId) return 0; } - vector devices; - unsigned platform_num = min(_platformId, platforms.size() - 1); - platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); + vector devices = getDevices(platforms, _platformId); if (devices.empty()) { ETHCL_LOG("No OpenCL devices found."); @@ -152,6 +162,13 @@ bool ethash_cl_miner::configureGPU() ); } +bool ethash_cl_miner::s_allowCPU = false; + +void ethash_cl_miner::allowCPU() +{ + s_allowCPU = true; +} + bool ethash_cl_miner::searchForAllDevices(function _callback) { vector platforms; @@ -175,8 +192,7 @@ bool ethash_cl_miner::searchForAllDevices(unsigned _platformId, function= platforms.size()) return false; - vector devices; - platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices); + vector devices = getDevices(platforms, _platformId); for (cl::Device const& device: devices) if (_callback(device)) return true; @@ -204,8 +220,7 @@ void ethash_cl_miner::doForAllDevices(unsigned _platformId, function= platforms.size()) return; - vector devices; - platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices); + vector devices = getDevices(platforms, _platformId); for (cl::Device const& device: devices) _callback(device); } @@ -253,8 +268,7 @@ bool ethash_cl_miner::init( ETHCL_LOG("Using platform: " << platforms[_platformId].getInfo().c_str()); // get GPU device of the default platform - vector devices; - platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices); + vector devices = getDevices(platforms, _platformId); if (devices.empty()) { ETHCL_LOG("No OpenCL devices found."); diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index 4c986053a..dc3f7eca0 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -41,6 +41,7 @@ public: static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0); static void listDevices(); static bool configureGPU(); + static void allowCPU(); bool init( uint8_t const* _dag, @@ -56,6 +57,9 @@ public: void search_chunk(uint8_t const* header, uint64_t target, search_hook& hook); private: + + static std::vector getDevices(std::vector const& _platforms, unsigned _platformId); + enum { c_max_search_results = 63, c_num_buffers = 2, c_hash_batch_size = 1024, c_search_batch_size = 1024*256 }; cl::Context m_context; @@ -70,4 +74,5 @@ private: unsigned m_workgroup_size; bool m_opencl_1_1; + static bool s_allowCPU; }; diff --git a/libethash-cl/ethash_cl_miner_kernel.cl b/libethash-cl/ethash_cl_miner_kernel.cl index 8567bb164..46c94f241 100644 --- a/libethash-cl/ethash_cl_miner_kernel.cl +++ b/libethash-cl/ethash_cl_miner_kernel.cl @@ -275,8 +275,6 @@ uint inner_loop_chunks(uint4 init, uint thread_id, __local uint* share, __global return fnv_reduce(mix); } - - uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, uint isolate) { uint4 mix = init; @@ -585,4 +583,4 @@ __kernel void ethash_search_chunks( uint slot = min(convert_uint(MAX_OUTPUTS), convert_uint(atomic_inc(&g_output[0]) + 1)); g_output[slot] = gid; } -} \ No newline at end of file +} diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 9ac4474ba..09ecfe1a3 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -366,6 +366,11 @@ void Ethash::GPUMiner::pause() stopWorking(); } +void Ethash::GPUMiner::allowCPU() +{ + return ethash_cl_miner::allowCPU(); +} + std::string Ethash::GPUMiner::platformInfo() { return ethash_cl_miner::platform_info(s_platformId, s_deviceId); diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 49a8ae006..91ca5f8fd 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -92,6 +92,7 @@ public: static void setDefaultDevice(unsigned) {} static void listDevices() {} static bool configureGPU() { return false; } + static void allowCPU() {} static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } protected: void kickOff() override @@ -121,6 +122,7 @@ public: static unsigned getNumDevices(); static void listDevices(); static bool configureGPU(); + static void allowCPU(); static void setDefaultPlatform(unsigned _id) { s_platformId = _id; } static void setDefaultDevice(unsigned _id) { s_deviceId = _id; } static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } From eaee35dd0b6f94b94a2e6946696fdf9848fbc7b0 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 11 Jun 2015 12:58:28 +0200 Subject: [PATCH 14/40] Refactor in OpenCL argument passing - No need for many different functions to set each single option for the miner. First we set all options and then we execute them. This way --list-devices will give different results with --alow-opencl-cpu and without it as it should. - If the user has no GPU with sufficient memory we no longer default to CPU. It's better to throw an error and let the user remove the argument. It's easy to miss the defaulting to CPU log message. --- ethminer/MinerAux.h | 36 ++++++++++++++------------------ libethash-cl/ethash_cl_miner.cpp | 8 ++----- libethash-cl/ethash_cl_miner.h | 3 +-- libethcore/Ethash.cpp | 11 ++++------ libethcore/Ethash.h | 11 ++-------- 5 files changed, 25 insertions(+), 44 deletions(-) diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index aac68f1a7..2816f637a 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -128,12 +128,9 @@ public: throw BadArgument(); } else if (arg == "--list-devices") - { - ProofOfWork::GPUMiner::listDevices(); - exit(0); - } + shouldListDevices = true; else if (arg == "--allow-opencl-cpu") - ProofOfWork::GPUMiner::allowCPU(); + clAllowCPU = true; else if (arg == "--phone-home" && i + 1 < argc) { string m = argv[++i]; @@ -177,18 +174,7 @@ public: else if (arg == "-C" || arg == "--cpu") m_minerType = MinerType::CPU; else if (arg == "-G" || arg == "--opencl") - { - if (!ProofOfWork::GPUMiner::configureGPU()) - { - cout << "No GPU device with sufficient memory was found. Defaulting to CPU" << endl; - m_minerType = MinerType::CPU; - } - else - { - m_minerType = MinerType::GPU; - miningThreads = 1; - } - } + m_minerType = MinerType::GPU; else if (arg == "--no-precompute") { precompute = false; @@ -264,13 +250,22 @@ public: void execute() { + if (shouldListDevices) + { + ProofOfWork::GPUMiner::listDevices(); + exit(0); + } + if (m_minerType == MinerType::CPU) ProofOfWork::CPUMiner::setNumInstances(miningThreads); else if (m_minerType == MinerType::GPU) { - ProofOfWork::GPUMiner::setDefaultPlatform(openclPlatform); - ProofOfWork::GPUMiner::setDefaultDevice(openclDevice); ProofOfWork::GPUMiner::setNumInstances(miningThreads); + if (!ProofOfWork::GPUMiner::configureGPU(openclPlatform, openclDevice, clAllowCPU)) + { + cout << "No GPU device with sufficient memory was found. Can't GPU mine. Remove the -G argument" << endl; + exit(1); + } } if (mode == OperationMode::DAGInit) doInitDAG(initDAG); @@ -495,7 +490,8 @@ private: unsigned openclPlatform = 0; unsigned openclDevice = 0; unsigned miningThreads = UINT_MAX; - unsigned dagChunks = 1; + bool shouldListDevices = false; + bool clAllowCPU = false; /// DAG initialisation param. unsigned initDAG = 0; diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 054985a38..db08d10c3 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -137,8 +137,9 @@ unsigned ethash_cl_miner::getNumDevices(unsigned _platformId) return devices.size(); } -bool ethash_cl_miner::configureGPU() +bool ethash_cl_miner::configureGPU(bool _allowCPU) { + s_allowCPU = _allowCPU; return searchForAllDevices([](cl::Device const _device) -> bool { cl_ulong result; @@ -164,11 +165,6 @@ bool ethash_cl_miner::configureGPU() bool ethash_cl_miner::s_allowCPU = false; -void ethash_cl_miner::allowCPU() -{ - s_allowCPU = true; -} - bool ethash_cl_miner::searchForAllDevices(function _callback) { vector platforms; diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index dc3f7eca0..44ec7eba9 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -40,8 +40,7 @@ public: static unsigned getNumDevices(unsigned _platformId = 0); static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0); static void listDevices(); - static bool configureGPU(); - static void allowCPU(); + static bool configureGPU(bool _allowCPU); bool init( uint8_t const* _dag, diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 09ecfe1a3..20ba539d1 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -366,11 +366,6 @@ void Ethash::GPUMiner::pause() stopWorking(); } -void Ethash::GPUMiner::allowCPU() -{ - return ethash_cl_miner::allowCPU(); -} - std::string Ethash::GPUMiner::platformInfo() { return ethash_cl_miner::platform_info(s_platformId, s_deviceId); @@ -386,9 +381,11 @@ void Ethash::GPUMiner::listDevices() return ethash_cl_miner::listDevices(); } -bool Ethash::GPUMiner::configureGPU() +bool Ethash::GPUMiner::configureGPU(unsigned _platformId, unsigned _deviceId, bool _allowCPU) { - return ethash_cl_miner::configureGPU(); + s_platformId = _platformId; + s_deviceId = _deviceId; + return ethash_cl_miner::configureGPU(_allowCPU); } #endif diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 91ca5f8fd..ee4c7d008 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -87,12 +87,8 @@ public: static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static std::string platformInfo(); - static void setDefaultPlatform(unsigned) {} - static void setDagChunks(unsigned) {} - static void setDefaultDevice(unsigned) {} static void listDevices() {} - static bool configureGPU() { return false; } - static void allowCPU() {} + static bool configureGPU(unsigned, unsigned, bool) { return false; } static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } protected: void kickOff() override @@ -121,10 +117,7 @@ public: static std::string platformInfo(); static unsigned getNumDevices(); static void listDevices(); - static bool configureGPU(); - static void allowCPU(); - static void setDefaultPlatform(unsigned _id) { s_platformId = _id; } - static void setDefaultDevice(unsigned _id) { s_deviceId = _id; } + static bool configureGPU(unsigned _platformId, unsigned _deviceId, bool _allowCPU); static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } protected: From 474705ba8089986056b98958865dacb202a586d2 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 11 Jun 2015 13:26:05 +0200 Subject: [PATCH 15/40] Styling changes --- ethminer/MinerAux.h | 72 +++++++++++++------------- libethash-cl/ethash_cl_miner_kernel.cl | 2 + 2 files changed, 38 insertions(+), 36 deletions(-) diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 2816f637a..65311b019 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -97,11 +97,11 @@ public: if ((arg == "-F" || arg == "--farm") && i + 1 < argc) { mode = OperationMode::Farm; - farmURL = argv[++i]; + m_farmURL = argv[++i]; } else if (arg == "--farm-recheck" && i + 1 < argc) try { - farmRecheckPeriod = stol(argv[++i]); + m_farmRecheckPeriod = stol(argv[++i]); } catch (...) { @@ -110,7 +110,7 @@ public: } else if (arg == "--opencl-platform" && i + 1 < argc) try { - openclPlatform = stol(argv[++i]); + m_openclPlatform = stol(argv[++i]); } catch (...) { @@ -119,8 +119,8 @@ public: } else if (arg == "--opencl-device" && i + 1 < argc) try { - openclDevice = stol(argv[++i]); - miningThreads = 1; + m_openclDevice = stol(argv[++i]); + m_miningThreads = 1; } catch (...) { @@ -128,16 +128,16 @@ public: throw BadArgument(); } else if (arg == "--list-devices") - shouldListDevices = true; + m_shouldListDevices = true; else if (arg == "--allow-opencl-cpu") - clAllowCPU = true; + m_clAllowCPU = true; else if (arg == "--phone-home" && i + 1 < argc) { string m = argv[++i]; if (isTrue(m)) - phoneHome = true; + m_phoneHome = true; else if (isFalse(m)) - phoneHome = false; + m_phoneHome = false; else { cerr << "Bad " << arg << " option: " << m << endl; @@ -146,7 +146,7 @@ public: } else if (arg == "--benchmark-warmup" && i + 1 < argc) try { - benchmarkWarmup = stol(argv[++i]); + m_benchmarkWarmup = stol(argv[++i]); } catch (...) { @@ -155,7 +155,7 @@ public: } else if (arg == "--benchmark-trial" && i + 1 < argc) try { - benchmarkTrial = stol(argv[++i]); + m_benchmarkTrial = stol(argv[++i]); } catch (...) { @@ -164,7 +164,7 @@ public: } else if (arg == "--benchmark-trials" && i + 1 < argc) try { - benchmarkTrials = stol(argv[++i]); + m_benchmarkTrials = stol(argv[++i]); } catch (...) { @@ -177,7 +177,7 @@ public: m_minerType = MinerType::GPU; else if (arg == "--no-precompute") { - precompute = false; + m_precompute = false; } else if ((arg == "-D" || arg == "--create-dag") && i + 1 < argc) { @@ -185,7 +185,7 @@ public: mode = OperationMode::DAGInit; try { - initDAG = stol(m); + m_initDAG = stol(m); } catch (...) { @@ -235,7 +235,7 @@ public: else if ((arg == "-t" || arg == "--mining-threads") && i + 1 < argc) { try { - miningThreads = stol(argv[++i]); + m_miningThreads = stol(argv[++i]); } catch (...) { @@ -250,29 +250,29 @@ public: void execute() { - if (shouldListDevices) + if (m_shouldListDevices) { ProofOfWork::GPUMiner::listDevices(); exit(0); } if (m_minerType == MinerType::CPU) - ProofOfWork::CPUMiner::setNumInstances(miningThreads); + ProofOfWork::CPUMiner::setNumInstances(m_miningThreads); else if (m_minerType == MinerType::GPU) { - ProofOfWork::GPUMiner::setNumInstances(miningThreads); - if (!ProofOfWork::GPUMiner::configureGPU(openclPlatform, openclDevice, clAllowCPU)) + ProofOfWork::GPUMiner::setNumInstances(m_miningThreads); + if (!ProofOfWork::GPUMiner::configureGPU(m_openclPlatform, m_openclDevice, m_clAllowCPU)) { cout << "No GPU device with sufficient memory was found. Can't GPU mine. Remove the -G argument" << endl; exit(1); } } if (mode == OperationMode::DAGInit) - doInitDAG(initDAG); + doInitDAG(m_initDAG); else if (mode == OperationMode::Benchmark) - doBenchmark(m_minerType, phoneHome, benchmarkWarmup, benchmarkTrial, benchmarkTrials); + doBenchmark(m_minerType, m_phoneHome, m_benchmarkWarmup, m_benchmarkTrial, m_benchmarkTrials); else if (mode == OperationMode::Farm) - doFarm(m_minerType, farmURL, farmRecheckPeriod); + doFarm(m_minerType, m_farmURL, m_farmRecheckPeriod); } static void streamHelp(ostream& _out) @@ -438,7 +438,7 @@ private: cnote << "Grabbing DAG for" << newSeedHash; if (!(dag = EthashAux::full(newSeedHash, true, [&](unsigned _pc){ cout << "\rCreating DAG. " << _pc << "% done..." << flush; return 0; }))) BOOST_THROW_EXCEPTION(DAGCreationFailure()); - if (precompute) + if (m_precompute) EthashAux::computeFull(sha3(newSeedHash), true); if (hh != current.headerHash) { @@ -487,23 +487,23 @@ private: /// Mining options MinerType m_minerType = MinerType::CPU; - unsigned openclPlatform = 0; - unsigned openclDevice = 0; - unsigned miningThreads = UINT_MAX; - bool shouldListDevices = false; - bool clAllowCPU = false; + unsigned m_openclPlatform = 0; + unsigned m_openclDevice = 0; + unsigned m_miningThreads = UINT_MAX; + bool m_shouldListDevices = false; + bool m_clAllowCPU = false; /// DAG initialisation param. - unsigned initDAG = 0; + unsigned m_initDAG = 0; /// Benchmarking params - bool phoneHome = true; - unsigned benchmarkWarmup = 3; - unsigned benchmarkTrial = 3; - unsigned benchmarkTrials = 5; + bool m_phoneHome = true; + unsigned m_benchmarkWarmup = 3; + unsigned m_benchmarkTrial = 3; + unsigned m_benchmarkTrials = 5; /// Farm params - string farmURL = "http://127.0.0.1:8545"; - unsigned farmRecheckPeriod = 500; - bool precompute = true; + string m_farmURL = "http://127.0.0.1:8545"; + unsigned m_farmRecheckPeriod = 500; + bool m_precompute = true; }; diff --git a/libethash-cl/ethash_cl_miner_kernel.cl b/libethash-cl/ethash_cl_miner_kernel.cl index 46c94f241..2143435ed 100644 --- a/libethash-cl/ethash_cl_miner_kernel.cl +++ b/libethash-cl/ethash_cl_miner_kernel.cl @@ -275,6 +275,8 @@ uint inner_loop_chunks(uint4 init, uint thread_id, __local uint* share, __global return fnv_reduce(mix); } + + uint inner_loop(uint4 init, uint thread_id, __local uint* share, __global hash128_t const* g_dag, uint isolate) { uint4 mix = init; From 7604f4c22476185f62e51e80faac22ee18a21321 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Thu, 11 Jun 2015 15:17:25 +0200 Subject: [PATCH 16/40] Smarter and more flexible GPU memory check - Added new option --cl-extragpumem with which you can let the OpenCL miner know how much GPU memory you believe your system would need for miscellaneous stuff like Windowing system rendering e.t.c. The default is 350 MB. - Added new option --curent-block with which you can let the miner know the current block during the configuration phase and as such help him provide a much more accurate calculation of how much GPU memory is required. - Added help(documentation) for some arguments that did not have one --- ethminer/MinerAux.h | 20 +++++++++++++++++++- libethash-cl/ethash_cl_miner.cpp | 17 +++++++++++------ libethash-cl/ethash_cl_miner.h | 7 ++++++- libethcore/Ethash.cpp | 10 ++++++++-- libethcore/Ethash.h | 10 ++++++++-- libethcore/EthashAux.cpp | 5 +++++ libethcore/EthashAux.h | 1 + 7 files changed, 58 insertions(+), 12 deletions(-) diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 65311b019..f49fbd70d 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -131,6 +132,8 @@ public: m_shouldListDevices = true; else if (arg == "--allow-opencl-cpu") m_clAllowCPU = true; + else if (arg == "--cl-extragpu-mem" && i + 1 < argc) + m_extraGPUMemory = 1000000 * stol(argv[++i]); else if (arg == "--phone-home" && i + 1 < argc) { string m = argv[++i]; @@ -175,6 +178,8 @@ public: m_minerType = MinerType::CPU; else if (arg == "-G" || arg == "--opencl") m_minerType = MinerType::GPU; + else if (arg == "--current-block" && i + 1 < argc) + m_currentBlock = stol(argv[++i]); else if (arg == "--no-precompute") { m_precompute = false; @@ -261,7 +266,13 @@ public: else if (m_minerType == MinerType::GPU) { ProofOfWork::GPUMiner::setNumInstances(m_miningThreads); - if (!ProofOfWork::GPUMiner::configureGPU(m_openclPlatform, m_openclDevice, m_clAllowCPU)) + if (!ProofOfWork::GPUMiner::configureGPU( + m_openclPlatform, + m_openclDevice, + m_clAllowCPU, + m_extraGPUMemory, + m_currentBlock + )) { cout << "No GPU device with sufficient memory was found. Can't GPU mine. Remove the -G argument" << endl; exit(1); @@ -303,6 +314,10 @@ public: << " --opencl-platform When mining using -G/--opencl use OpenCL platform n (default: 0)." << endl << " --opencl-device When mining using -G/--opencl use OpenCL device n (default: 0)." << endl << " -t, --mining-threads Limit number of CPU/GPU miners to n (default: use everything available on selected platform)" << endl + << " --allow-opencl-cpu Allows CPU to be considered as an OpenCL device if the OpenCL platform supports it." << endl + << " --list-devices List the detected OpenCL devices and exit." < m_currentBlock; + // default value is 350MB of GPU memory for other stuff (windows system rendering, e.t.c.) + unsigned m_extraGPUMemory = 350000000; /// DAG initialisation param. unsigned m_initDAG = 0; diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index db08d10c3..5f36393c6 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -32,11 +32,11 @@ #include #include #include +#include #include "ethash_cl_miner.h" #include "ethash_cl_miner_kernel.h" #define ETHASH_BYTES 32 -#define ETHASH_CL_MINIMUM_MEMORY 2000000000 // workaround lame platforms #if !CL_VERSION_1_2 @@ -137,14 +137,18 @@ unsigned ethash_cl_miner::getNumDevices(unsigned _platformId) return devices.size(); } -bool ethash_cl_miner::configureGPU(bool _allowCPU) +bool ethash_cl_miner::configureGPU(bool _allowCPU, unsigned _extraGPUMemory, boost::optional _currentBlock) { s_allowCPU = _allowCPU; - return searchForAllDevices([](cl::Device const _device) -> bool + s_extraRequiredGPUMem = _extraGPUMemory; + // by default let's only consider the DAG of the first epoch + uint64_t dagSize = _currentBlock ? ethash_get_datasize(*_currentBlock) : 1073739904U; + uint64_t requiredSize = dagSize + _extraGPUMemory; + return searchForAllDevices([&requiredSize](cl::Device const _device) -> bool { cl_ulong result; _device.getInfo(CL_DEVICE_GLOBAL_MEM_SIZE, &result); - if (result >= ETHASH_CL_MINIMUM_MEMORY) + if (result >= requiredSize) { ETHCL_LOG( "Found suitable OpenCL device [" << _device.getInfo() @@ -156,7 +160,7 @@ bool ethash_cl_miner::configureGPU(bool _allowCPU) ETHCL_LOG( "OpenCL device " << _device.getInfo() << " has insufficient GPU memory." << result << - " bytes of memory found < " << ETHASH_CL_MINIMUM_MEMORY << " bytes of memory required" + " bytes of memory found < " << requiredSize << " bytes of memory required" ); return false; } @@ -164,6 +168,7 @@ bool ethash_cl_miner::configureGPU(bool _allowCPU) } bool ethash_cl_miner::s_allowCPU = false; +unsigned ethash_cl_miner::s_extraRequiredGPUMem; bool ethash_cl_miner::searchForAllDevices(function _callback) { @@ -279,7 +284,7 @@ bool ethash_cl_miner::init( // configure chunk number depending on max allocateable memory cl_ulong result; device.getInfo(CL_DEVICE_MAX_MEM_ALLOC_SIZE, &result); - if (result >= ETHASH_CL_MINIMUM_MEMORY) + if (result >= _dagSize) { m_dagChunksNum = 1; ETHCL_LOG("Using 1 big chunk. Max OpenCL allocateable memory is" << result); diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index 44ec7eba9..b17fdeeb4 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -12,6 +12,7 @@ #include "cl.hpp" #endif +#include #include #include #include @@ -40,7 +41,7 @@ public: static unsigned getNumDevices(unsigned _platformId = 0); static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0); static void listDevices(); - static bool configureGPU(bool _allowCPU); + static bool configureGPU(bool _allowCPU, unsigned _extraGPUMemory, boost::optional _currentBlock); bool init( uint8_t const* _dag, @@ -73,5 +74,9 @@ private: unsigned m_workgroup_size; bool m_opencl_1_1; + /// Allow CPU to appear as an OpenCL device or not. Default is false static bool s_allowCPU; + /// GPU memory required for other things, like window rendering e.t.c. + /// User can set it via the --cl-extragpu-mem argument. + static unsigned s_extraRequiredGPUMem; }; diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 20ba539d1..8600dd51a 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -381,11 +381,17 @@ void Ethash::GPUMiner::listDevices() return ethash_cl_miner::listDevices(); } -bool Ethash::GPUMiner::configureGPU(unsigned _platformId, unsigned _deviceId, bool _allowCPU) +bool Ethash::GPUMiner::configureGPU( + unsigned _platformId, + unsigned _deviceId, + bool _allowCPU, + unsigned _extraGPUMemory, + boost::optional _currentBlock +) { s_platformId = _platformId; s_deviceId = _deviceId; - return ethash_cl_miner::configureGPU(_allowCPU); + return ethash_cl_miner::configureGPU(_allowCPU, _extraGPUMemory, _currentBlock); } #endif diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index ee4c7d008..d9584f0d4 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -88,7 +88,7 @@ public: static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static std::string platformInfo(); static void listDevices() {} - static bool configureGPU(unsigned, unsigned, bool) { return false; } + static bool configureGPU(unsigned, unsigned, bool, unsigned, boost::optional) { return false; } static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } protected: void kickOff() override @@ -117,7 +117,13 @@ public: static std::string platformInfo(); static unsigned getNumDevices(); static void listDevices(); - static bool configureGPU(unsigned _platformId, unsigned _deviceId, bool _allowCPU); + static bool configureGPU( + unsigned _platformId, + unsigned _deviceId, + bool _allowCPU, + unsigned _extraGPUMemory, + boost::optional _currentBlock + ); static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } protected: diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 0c1e84ebc..51a606ff8 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -54,6 +54,11 @@ uint64_t EthashAux::cacheSize(BlockInfo const& _header) return ethash_get_cachesize((uint64_t)_header.number); } +uint64_t EthashAux::dataSize(uint64_t _blockNumber) +{ + return ethash_get_datasize(_blockNumber); +} + h256 EthashAux::seedHash(unsigned _number) { unsigned epoch = _number / ETHASH_EPOCH_LENGTH; diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index e6fed519f..47180bfd2 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -66,6 +66,7 @@ public: static h256 seedHash(unsigned _number); static uint64_t number(h256 const& _seedHash); static uint64_t cacheSize(BlockInfo const& _header); + static uint64_t dataSize(uint64_t _blockNumber); static LightType light(h256 const& _seedHash); From 9e9a33b7134a8565cc478b647090d87fb9fa82fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Thu, 11 Jun 2015 11:17:57 +0200 Subject: [PATCH 17/40] Set stack memory limit on OSX. --- cmake/EthCompilerSettings.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake index 53535a489..d21a3d4b1 100644 --- a/cmake/EthCompilerSettings.cmake +++ b/cmake/EthCompilerSettings.cmake @@ -55,6 +55,11 @@ else () message(WARNING "Your compiler is not tested, if you run into any issues, we'd welcome any patches.") endif () +# Set stack memory limits +if (APPLE) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-stack_size,1000000") +endif() + if (PROFILING AND (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))) set(CMAKE_CXX_FLAGS "-g ${CMAKE_CXX_FLAGS}") set(CMAKE_C_FLAGS "-g ${CMAKE_C_FLAGS}") From 7a557e42df3afc8d6c9702753f4fe56eeb49031d Mon Sep 17 00:00:00 2001 From: yann300 Date: Thu, 11 Jun 2015 15:46:29 +0200 Subject: [PATCH 18/40] small changed based on comments --- libethereum/BlockChain.cpp | 6 +++--- mix/ClientModel.cpp | 3 +-- mix/ClientModel.h | 1 - mix/QFunctionDefinition.cpp | 1 - mix/QVariableDeclaration.cpp | 9 +++------ 5 files changed, 7 insertions(+), 13 deletions(-) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 1d53e73f9..5a0b085a7 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -1068,11 +1068,11 @@ VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function 0; } - m_client->resetState(m_accounts, Secret(m_currentScenario.value("miner").toMap().value("secret").toString().toStdString())); + m_client->resetState(m_accounts, Secret(_scenario.value("miner").toMap().value("secret").toString().toStdString())); if (m_queueTransactions.count() > 0 && trToExecute) { setupExecutionChain(); diff --git a/mix/ClientModel.h b/mix/ClientModel.h index 32348b603..b5b783b3d 100644 --- a/mix/ClientModel.h +++ b/mix/ClientModel.h @@ -273,7 +273,6 @@ private: std::map m_stdContractNames; CodeModel* m_codeModel = nullptr; QList m_queueTransactions; - QVariantMap m_currentScenario; mutable boost::shared_mutex x_queueTransactions; }; diff --git a/mix/QFunctionDefinition.cpp b/mix/QFunctionDefinition.cpp index 52d8ad30c..1a1dd8083 100644 --- a/mix/QFunctionDefinition.cpp +++ b/mix/QFunctionDefinition.cpp @@ -37,7 +37,6 @@ QFunctionDefinition::QFunctionDefinition(QObject* _parent, dev::solidity::Functi QFunctionDefinition::QFunctionDefinition(QObject* _parent, ASTPointer const& _f): QBasicNodeDefinition(_parent, _f.get()), m_hash(dev::sha3(_f->externalSignature())), m_fullHash(dev::sha3(_f->externalSignature())) { - for (unsigned i = 0; i < _f->getParameters().size(); ++i) m_parameters.append(new QVariableDeclaration(parent(), _f->getParameters().at(i))); diff --git a/mix/QVariableDeclaration.cpp b/mix/QVariableDeclaration.cpp index 4299e34ee..a086585cd 100644 --- a/mix/QVariableDeclaration.cpp +++ b/mix/QVariableDeclaration.cpp @@ -33,23 +33,20 @@ namespace mix QVariableDeclaration::QVariableDeclaration(QObject* _parent, ASTPointer const _v): QBasicNodeDefinition(_parent, _v.get()), - m_type(new QSolidityType(this, CodeModel::nodeType(_v->getType().get()))) + m_type(new QSolidityType(this, CodeModel::nodeType(_v->getType().get()))), m_isIndexed(_v->isIndexed()) { - m_isIndexed = _v->isIndexed(); } QVariableDeclaration::QVariableDeclaration(QObject* _parent, std::string const& _name, SolidityType const& _type, bool _isIndexed): QBasicNodeDefinition(_parent, _name), - m_type(new QSolidityType(_parent, _type)) + m_type(new QSolidityType(_parent, _type)), m_isIndexed(_isIndexed) { - m_isIndexed = _isIndexed; } QVariableDeclaration::QVariableDeclaration(QObject* _parent, std::string const& _name, solidity::Type const* _type, bool _isIndexed): QBasicNodeDefinition(_parent, _name), - m_type(new QSolidityType(this, CodeModel::nodeType(_type))) + m_type(new QSolidityType(this, CodeModel::nodeType(_type))), m_isIndexed(_isIndexed) { - m_isIndexed = _isIndexed; } QSolidityType::QSolidityType(QObject* _parent, SolidityType const& _type): From 1593d20e6c9d3b0d57b4d743346f4163f793ec1d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 11 Jun 2015 22:53:21 +0900 Subject: [PATCH 19/40] Fix for FixedHash::operator~(). --- libdevcore/FixedHash.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 88bc0fe95..2d1822b2c 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -100,7 +100,7 @@ public: FixedHash operator|(FixedHash const& _c) const { return FixedHash(*this) |= _c; } FixedHash& operator&=(FixedHash const& _c) { for (unsigned i = 0; i < N; ++i) m_data[i] &= _c.m_data[i]; return *this; } FixedHash operator&(FixedHash const& _c) const { return FixedHash(*this) &= _c; } - FixedHash& operator~() { for (unsigned i = 0; i < N; ++i) m_data[i] = ~m_data[i]; return *this; } + FixedHash operator~() const { FixedHash ret; for (unsigned i = 0; i < N; ++i) ret[i] = ~m_data[i]; return ret; } /// @returns true if all bytes in @a _c are set in this object. bool contains(FixedHash const& _c) const { return (*this & _c) == _c; } From 237d044a73fe0b28a4b61eb676ac08300d090095 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 12 Jun 2015 00:41:28 +0900 Subject: [PATCH 20/40] Reprocess in eth -i, don't network by default. --- eth/main.cpp | 29 ++++++++++++++++++++++++++--- libethereum/State.cpp | 7 ++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/eth/main.cpp b/eth/main.cpp index 5497a2cda..a7f483966 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -108,6 +108,7 @@ void interactiveHelp() << " exportconfig Export the config (.RLP) to the path provided." << endl << " importconfig Import the config (.RLP) from the path provided." << endl << " inspect Dumps a contract to /.evm." << endl + << " reprocess Reprocess a given block." << endl << " dumptrace Dumps a transaction trace" << endl << "to . should be one of pretty, standard, standard+." << endl << " dumpreceipt Dumps a transation receipt." << endl << " exit Exits the application." << endl; @@ -806,13 +807,19 @@ int main(int argc, char** argv) cout << "Transaction Signer: " << signingKey << endl; cout << "Mining Benefactor: " << beneficiary << endl; - web3.startNetwork(); - cout << "Node ID: " << web3.enode() << endl; + + if (bootstrap || !remoteHost.empty()) + { + web3.startNetwork(); + cout << "Node ID: " << web3.enode() << endl; + } + else + cout << "Networking disabled. To start, use netstart or pass -b or a remote host." << endl; if (bootstrap) for (auto const& i: Host::pocHosts()) web3.requirePeer(i.first, i.second); - if (remoteHost.size()) + if (!remoteHost.empty()) web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort)); #if ETH_JSONRPC || !ETH_TRUE @@ -1403,6 +1410,22 @@ int main(int argc, char** argv) cout << "Hex: " << toHex(rb) << endl; cout << r << endl; } + else if (c && cmd == "reprocess") + { + string block; + iss >> block; + h256 blockHash; + try + { + if (block.size() == 64 || block.size() == 66) + blockHash = h256(block); + else + blockHash = c->blockChain().numberHash(stoi(block)); + c->state(blockHash); + } + catch (...) + {} + } else if (c && cmd == "dumptrace") { unsigned block; diff --git a/libethereum/State.cpp b/libethereum/State.cpp index c80863d2f..a4b784b6f 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -141,7 +141,12 @@ State::State(OverlayDB const& _db, BlockChain const& _bc, h256 _h, ImportRequire // 2. Enact the block's transactions onto this state. m_ourAddress = bi.coinbaseAddress; - enact(BlockChain::verifyBlock(b), _bc, _ir); + boost::timer t; + auto vb = BlockChain::verifyBlock(b); + cnote << "verifyBlock:" << t.elapsed(); + t.restart(); + enact(vb, _bc, _ir); + cnote << "enact:" << t.elapsed(); } else { From cb133837c4f27df8c9e86652358da16ecf53a924 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Thu, 11 Jun 2015 18:53:29 +0300 Subject: [PATCH 21/40] expectOut fill section to vmTests --- test/TestHelper.cpp | 2 ++ test/libevm/vm.cpp | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 873ea21e2..733ccb6d0 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -352,6 +352,8 @@ void ImportTest::exportTest(bytes const& _output, State const& _statePost) BOOST_CHECK_MESSAGE((m_TestObject["out"].get_str() == m_TestObject["expectOut"].get_str()), warning); else BOOST_WARN_MESSAGE((m_TestObject["out"].get_str() == m_TestObject["expectOut"].get_str()), warning); + + m_TestObject.erase(m_TestObject.find("expectOut")); } // export logs diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index ec66837e1..5bbab2e1c 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -388,6 +388,19 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) o["callcreates"] = fev.exportCallCreates(); o["out"] = output.size() > 4096 ? "#" + toString(output.size()) : toHex(output, 2, HexPrefix::Add); + + // compare expected output with post output + if (o.count("expectOut") > 0) + { + std::string warning = "Check State: Error! Unexpected output: " + o["out"].get_str() + " Expected: " + o["expectOut"].get_str(); + if (Options::get().checkState) + BOOST_CHECK_MESSAGE((o["out"].get_str() == o["expectOut"].get_str()), warning); + else + BOOST_WARN_MESSAGE((o["out"].get_str() == o["expectOut"].get_str()), warning); + + o.erase(o.find("expectOut")); + } + o["gas"] = toCompactHex(fev.gas, HexPrefix::Add, 1); o["logs"] = exportLog(fev.sub.logs); } From 566b2b635447cc3313817eb8482ae04af2a99eb7 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 11 Jun 2015 18:41:31 +0200 Subject: [PATCH 22/40] resync after downloading unknown new block --- libethereum/EthereumHost.cpp | 36 +++++++++++++++++++++++++++++------- libethereum/EthereumHost.h | 2 ++ libp2p/Host.cpp | 19 ++++++++++++------- libp2p/Host.h | 1 + 4 files changed, 44 insertions(+), 14 deletions(-) diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 33f95695b..4609fddb6 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -81,6 +81,7 @@ void EthereumHost::reset() m_hashMan.reset(m_chain.number() + 1); m_needSyncBlocks = true; m_needSyncHashes = true; + m_syncingNewHashes = false; m_syncingLatestHash = h256(); m_syncingTotalDifficulty = 0; m_latestBlockSent = h256(); @@ -88,6 +89,14 @@ void EthereumHost::reset() m_hashes.clear(); } +void EthereumHost::resetSyncTo(h256 const& _h) +{ + m_needSyncHashes = true; + m_needSyncBlocks = true; + m_syncingLatestHash = _h; + m_syncingNewHashes = false; +} + void EthereumHost::doWork() { bool netChange = ensureInitialised(); @@ -366,8 +375,13 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool } if (_complete) { + clog(NetMessageSummary) << "Start new blocks download..."; m_needSyncBlocks = true; - continueSync(); + m_syncingNewHashes = true; + m_man.resetToChain(m_hashes); + m_hashes.clear(); + m_hashMan.reset(m_chain.number() + 1); + continueSync(_peer); } else if (syncByNumber && m_hashMan.isComplete()) { @@ -425,6 +439,7 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) unsigned unknown = 0; unsigned got = 0; unsigned repeated = 0; + h256 lastUnknown; for (unsigned i = 0; i < itemCount; ++i) { @@ -453,6 +468,7 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) break; case ImportResult::UnknownParent: + lastUnknown = h; unknown++; break; @@ -467,6 +483,13 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) } clog(NetMessageSummary) << dec << success << "imported OK," << unknown << "with unknown parents," << future << "with future timestamps," << got << " already known," << repeated << " repeats received."; + + if (m_syncingNewHashes && unknown > 0) + { + _peer->m_latestHash = lastUnknown; + resetSyncTo(lastUnknown); + } + continueSync(_peer); } @@ -486,7 +509,7 @@ void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) { RecursiveGuard l(x_sync); - if (isSyncing_UNSAFE() || _peer->isConversing()) + if ((isSyncing_UNSAFE() || _peer->isConversing()) && !m_syncingNewHashes) { clog(NetMessageSummary) << "Ignoring new blocks since we're already downloading."; return; @@ -526,9 +549,7 @@ void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) clog(NetMessageSummary) << "Received block with no known parent. Resyncing..."; _peer->m_latestHash = h; _peer->m_totalDifficulty = difficulty; - m_needSyncHashes = true; - m_needSyncBlocks = true; - m_syncingLatestHash = h; + resetSyncTo(h);; sync = true; } } @@ -646,7 +667,7 @@ void EthereumHost::continueSync(EthereumPeer* _peer) { _peer->requestHashes(m_syncingLatestHash); m_syncingV61 = false; - m_estimatedHashes = _peer->m_expectedHashes; + m_estimatedHashes = _peer->m_expectedHashes - (_peer->m_protocolVersion == protocolVersion() ? 0 : c_chainReorgSize); } else _peer->setIdle(); @@ -658,6 +679,7 @@ void EthereumHost::continueSync(EthereumPeer* _peer) { // Done our chain-get. m_needSyncBlocks = false; + m_syncingNewHashes = false; clog(NetNote) << "Chain download complete."; // 1/100th for each useful block hash. _peer->addRating(m_man.chainSize() / 100); //TODO: what about other peers? @@ -742,6 +764,6 @@ HashChainStatus EthereumHost::status() RecursiveGuard l(x_sync); if (m_syncingV61) return HashChainStatus { static_cast(m_hashMan.chainSize()), static_cast(m_hashMan.gotCount()), false }; - return HashChainStatus { m_estimatedHashes > 0 ? m_estimatedHashes - c_chainReorgSize : 0, static_cast(m_hashes.size()), m_estimatedHashes > 0 }; + return HashChainStatus { m_estimatedHashes > 0 ? m_estimatedHashes : 0, static_cast(m_hashes.size()), m_estimatedHashes > 0 }; } diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h index 17684fea1..392e234f3 100644 --- a/libethereum/EthereumHost.h +++ b/libethereum/EthereumHost.h @@ -97,6 +97,7 @@ private: void foreachPeerPtr(std::function)> const& _f) const; void foreachPeer(std::function const& _f) const; bool isSyncing_UNSAFE() const; + void resetSyncTo(h256 const& _h); /// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network. void doWork(); @@ -151,6 +152,7 @@ private: bool m_needSyncBlocks = true; ///< Indicates if we still need to download some blocks h256 m_syncingLatestHash; ///< Latest block's hash, as of the current sync. u256 m_syncingTotalDifficulty; ///< Latest block's total difficulty, as of the current sync. + bool m_syncingNewHashes = false; ///< True if currently downloading hashes received with NewHashes h256s m_hashes; ///< List of hashes with unknown block numbers. Used for PV60 chain downloading and catching up to a particular unknown unsigned m_estimatedHashes = 0; ///< Number of estimated hashes for the last peer over PV60. Used for status reporting only. bool m_syncingV61 = false; ///< True if recent activity was over pv61+. Used for status reporting only. diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index f4cceebf2..628b59767 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -61,17 +61,22 @@ ReputationManager::ReputationManager() void ReputationManager::noteRude(Session const& _s, std::string const& _sub) { - m_nodes[make_pair(_s.id(), _s.info().clientVersion)].subs[_sub].isRude = true; + DEV_WRITE_GUARDED(x_nodes) + m_nodes[make_pair(_s.id(), _s.info().clientVersion)].subs[_sub].isRude = true; } bool ReputationManager::isRude(Session const& _s, std::string const& _sub) const { - auto nit = m_nodes.find(make_pair(_s.id(), _s.info().clientVersion)); - if (nit == m_nodes.end()) - return false; - auto sit = nit->second.subs.find(_sub); - bool ret = sit == nit->second.subs.end() ? false : sit->second.isRude; - return _sub.empty() ? ret : (ret || isRude(_s)); + DEV_READ_GUARDED(x_nodes) + { + auto nit = m_nodes.find(make_pair(_s.id(), _s.info().clientVersion)); + if (nit == m_nodes.end()) + return false; + auto sit = nit->second.subs.find(_sub); + bool ret = sit == nit->second.subs.end() ? false : sit->second.isRude; + return _sub.empty() ? ret : (ret || isRude(_s)); + } + return false; } Host::Host(std::string const& _clientVersion, NetworkPreferences const& _n, bytesConstRef _restoreNetwork): diff --git a/libp2p/Host.h b/libp2p/Host.h index 132dd379a..b32c495cb 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -99,6 +99,7 @@ public: private: std::unordered_map, Reputation> m_nodes; ///< Nodes that were impolite while syncing. We avoid syncing from these if possible. + SharedMutex mutable x_nodes; }; /** From 057311778ce257978005b85f992c57ddcbc9faef Mon Sep 17 00:00:00 2001 From: subtly Date: Thu, 11 Jun 2015 19:15:53 -0400 Subject: [PATCH 23/40] Prep for cleanup, subprotocol packet queues, and framing. Disown rlpxsocket from handshake and rename FrameIO to FrameCoder. --- libp2p/Host.cpp | 6 +- libp2p/Host.h | 5 +- .../{RLPxFrameIO.cpp => RLPXFrameCoder.cpp} | 30 +++++----- libp2p/{RLPxFrameIO.h => RLPXFrameCoder.h} | 49 +++------------- libp2p/RLPXSocket.cpp | 0 libp2p/RLPXSocket.h | 56 +++++++++++++++++++ libp2p/RLPxHandshake.cpp | 6 +- libp2p/RLPxHandshake.h | 9 +-- libp2p/Session.cpp | 35 ++++++------ libp2p/Session.h | 11 ++-- 10 files changed, 118 insertions(+), 89 deletions(-) rename libp2p/{RLPxFrameIO.cpp => RLPXFrameCoder.cpp} (89%) rename libp2p/{RLPxFrameIO.h => RLPXFrameCoder.h} (67%) create mode 100644 libp2p/RLPXSocket.cpp create mode 100644 libp2p/RLPXSocket.h diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index f47db3c2b..c5e209d70 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -172,7 +172,7 @@ void Host::doneWorking() m_sessions.clear(); } -void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io, bi::tcp::endpoint _endpoint) +void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameCoder* _io, std::shared_ptr const& _s) { // session maybe ingress or egress so m_peers and node table entries may not exist shared_ptr p; @@ -192,7 +192,7 @@ void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io } if (p->isOffline()) p->m_lastConnected = std::chrono::system_clock::now(); - p->endpoint.address = _endpoint.address(); + p->endpoint.address = _s->remoteEndpoint().address(); auto protocolVersion = _rlp[0].toInt(); auto clientVersion = _rlp[1].toString(); @@ -211,7 +211,7 @@ void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io clog(NetMessageSummary) << "Hello: " << clientVersion << "V[" << protocolVersion << "]" << _id << showbase << capslog.str() << dec << listenPort; // create session so disconnects are managed - auto ps = make_shared(this, _io, p, PeerSessionInfo({_id, clientVersion, _endpoint.address().to_string(), listenPort, chrono::steady_clock::duration(), _rlp[2].toSet(), 0, map()})); + auto ps = make_shared(this, _io, _s, p, PeerSessionInfo({_id, clientVersion, p->endpoint.address.to_string(), listenPort, chrono::steady_clock::duration(), _rlp[2].toSet(), 0, map()})); if (protocolVersion < dev::p2p::c_protocolVersion - 1) { ps->disconnect(IncompatibleProtocol); diff --git a/libp2p/Host.h b/libp2p/Host.h index 3c7ce257a..95b77d5c9 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -40,7 +40,8 @@ #include "HostCapability.h" #include "Network.h" #include "Peer.h" -#include "RLPxFrameIO.h" +#include "RLPXSocket.h" +#include "RLPXFrameCoder.h" #include "Common.h" namespace ba = boost::asio; namespace bi = ba::ip; @@ -158,7 +159,7 @@ public: NodeId id() const { return m_alias.pub(); } /// Validates and starts peer session, taking ownership of _io. Disconnects and returns false upon error. - void startPeerSession(Public const& _id, RLP const& _hello, RLPXFrameIO* _io, bi::tcp::endpoint _endpoint); + void startPeerSession(Public const& _id, RLP const& _hello, RLPXFrameCoder* _io, std::shared_ptr const& _s); protected: void onNodeTableEvent(NodeId const& _n, NodeTableEventType const& _e); diff --git a/libp2p/RLPxFrameIO.cpp b/libp2p/RLPXFrameCoder.cpp similarity index 89% rename from libp2p/RLPxFrameIO.cpp rename to libp2p/RLPXFrameCoder.cpp index 4fa8557ba..c4bb46814 100644 --- a/libp2p/RLPxFrameIO.cpp +++ b/libp2p/RLPXFrameCoder.cpp @@ -14,16 +14,14 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file RLPXFrameIO.cpp +/** @file RLPXFrameCoder.cpp * @author Alex Leverington * @date 2015 */ -#include "RLPxFrameIO.h" +#include "RLPXFrameCoder.h" + #include -#include "Host.h" -#include "Session.h" -#include "Peer.h" #include "RLPxHandshake.h" using namespace std; @@ -31,7 +29,7 @@ using namespace dev; using namespace dev::p2p; using namespace CryptoPP; -RLPXFrameIO::RLPXFrameIO(RLPXHandshake const& _init): m_socket(_init.m_socket) +RLPXFrameCoder::RLPXFrameCoder(RLPXHandshake const& _init) { // we need: // originated? @@ -94,7 +92,7 @@ RLPXFrameIO::RLPXFrameIO(RLPXHandshake const& _init): m_socket(_init.m_socket) m_ingressMac.Update(keyMaterial.data(), keyMaterial.size()); } -void RLPXFrameIO::writeSingleFramePacket(bytesConstRef _packet, bytes& o_bytes) +void RLPXFrameCoder::writeSingleFramePacket(bytesConstRef _packet, bytes& o_bytes) { // _packet = type || rlpList() @@ -126,7 +124,7 @@ void RLPXFrameIO::writeSingleFramePacket(bytesConstRef _packet, bytes& o_bytes) egressDigest().ref().copyTo(macRef); } -bool RLPXFrameIO::authAndDecryptHeader(bytesRef io) +bool RLPXFrameCoder::authAndDecryptHeader(bytesRef io) { asserts(io.size() == h256::size); updateIngressMACWithHeader(io); @@ -138,7 +136,7 @@ bool RLPXFrameIO::authAndDecryptHeader(bytesRef io) return true; } -bool RLPXFrameIO::authAndDecryptFrame(bytesRef io) +bool RLPXFrameCoder::authAndDecryptFrame(bytesRef io) { bytesRef cipherText(io.cropped(0, io.size() - h128::size)); updateIngressMACWithFrame(cipherText); @@ -149,7 +147,7 @@ bool RLPXFrameIO::authAndDecryptFrame(bytesRef io) return true; } -h128 RLPXFrameIO::egressDigest() +h128 RLPXFrameCoder::egressDigest() { SHA3_256 h(m_egressMac); h128 digest; @@ -157,7 +155,7 @@ h128 RLPXFrameIO::egressDigest() return digest; } -h128 RLPXFrameIO::ingressDigest() +h128 RLPXFrameCoder::ingressDigest() { SHA3_256 h(m_ingressMac); h128 digest; @@ -165,29 +163,29 @@ h128 RLPXFrameIO::ingressDigest() return digest; } -void RLPXFrameIO::updateEgressMACWithHeader(bytesConstRef _headerCipher) +void RLPXFrameCoder::updateEgressMACWithHeader(bytesConstRef _headerCipher) { updateMAC(m_egressMac, _headerCipher.cropped(0, 16)); } -void RLPXFrameIO::updateEgressMACWithFrame(bytesConstRef _cipher) +void RLPXFrameCoder::updateEgressMACWithFrame(bytesConstRef _cipher) { m_egressMac.Update(_cipher.data(), _cipher.size()); updateMAC(m_egressMac); } -void RLPXFrameIO::updateIngressMACWithHeader(bytesConstRef _headerCipher) +void RLPXFrameCoder::updateIngressMACWithHeader(bytesConstRef _headerCipher) { updateMAC(m_ingressMac, _headerCipher.cropped(0, 16)); } -void RLPXFrameIO::updateIngressMACWithFrame(bytesConstRef _cipher) +void RLPXFrameCoder::updateIngressMACWithFrame(bytesConstRef _cipher) { m_ingressMac.Update(_cipher.data(), _cipher.size()); updateMAC(m_ingressMac); } -void RLPXFrameIO::updateMAC(SHA3_256& _mac, bytesConstRef _seed) +void RLPXFrameCoder::updateMAC(SHA3_256& _mac, bytesConstRef _seed) { if (_seed.size() && _seed.size() != h128::size) asserts(false); diff --git a/libp2p/RLPxFrameIO.h b/libp2p/RLPXFrameCoder.h similarity index 67% rename from libp2p/RLPxFrameIO.h rename to libp2p/RLPXFrameCoder.h index 0f0504e48..7c5eedbff 100644 --- a/libp2p/RLPxFrameIO.h +++ b/libp2p/RLPXFrameCoder.h @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with cpp-ethereum. If not, see . */ -/** @file RLPXFrameIO.h +/** @file RLPXFrameCoder.h * @author Alex Leverington * @date 2015 */ @@ -23,13 +23,10 @@ #pragma once #include -#include +#include #include #include -#include #include "Common.h" -namespace ba = boost::asio; -namespace bi = boost::asio::ip; namespace dev { @@ -39,45 +36,21 @@ namespace p2p class RLPXHandshake; /** - * @brief Encoder/decoder transport for RLPx connections established by RLPXHandshake. - * Managed (via shared_ptr) socket for use by RLPXHandshake and RLPXFrameIO. - * - * Thread Safety - * Distinct Objects: Safe. - * Shared objects: Unsafe. - * * an instance method must not be called concurrently - * * a writeSingleFramePacket can be called concurrent to authAndDecryptHeader OR authAndDecryptFrame - */ -class RLPXSocket: public std::enable_shared_from_this -{ -public: - RLPXSocket(bi::tcp::socket* _socket): m_socket(std::move(*_socket)) {} - ~RLPXSocket() { close(); } - - bool isConnected() const { return m_socket.is_open(); } - void close() { try { boost::system::error_code ec; m_socket.shutdown(bi::tcp::socket::shutdown_both, ec); if (m_socket.is_open()) m_socket.close(); } catch (...){} } - bi::tcp::endpoint remoteEndpoint() { try { return m_socket.remote_endpoint(); } catch (...){ return bi::tcp::endpoint(); } } - bi::tcp::socket& ref() { return m_socket; } - -protected: - bi::tcp::socket m_socket; -}; - -/** - * @brief Encoder/decoder transport for RLPx connections established by RLPXHandshake. + * @brief Encoder/decoder transport for RLPx connection established by RLPXHandshake. * * Thread Safety * Distinct Objects: Safe. * Shared objects: Unsafe. */ -class RLPXFrameIO +class RLPXFrameCoder { + friend class RLPXFrameIOMux; friend class Session; public: /// Constructor. /// Requires instance of RLPXHandshake which has completed first two phases of handshake. - RLPXFrameIO(RLPXHandshake const& _init); - ~RLPXFrameIO() {} + RLPXFrameCoder(RLPXHandshake const& _init); + ~RLPXFrameCoder() {} /// Encrypt _packet as RLPx frame. void writeSingleFramePacket(bytesConstRef _packet, bytes& o_bytes); @@ -93,7 +66,7 @@ public: /// Return first 16 bytes of current digest from ingress mac. h128 ingressDigest(); - + protected: /// Update state of egress MAC with frame header. void updateEgressMACWithHeader(bytesConstRef _headerCipher); @@ -106,9 +79,7 @@ protected: /// Update state of ingress MAC with frame. void updateIngressMACWithFrame(bytesConstRef _cipher); - - bi::tcp::socket& socket() { return m_socket->ref(); } - + private: /// Update state of _mac. void updateMAC(CryptoPP::SHA3_256& _mac, bytesConstRef _seed = bytesConstRef()); @@ -125,8 +96,6 @@ private: CryptoPP::SHA3_256 m_egressMac; ///< State of MAC for egress ciphertext. CryptoPP::SHA3_256 m_ingressMac; ///< State of MAC for ingress ciphertext. - - std::shared_ptr m_socket; }; } diff --git a/libp2p/RLPXSocket.cpp b/libp2p/RLPXSocket.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/libp2p/RLPXSocket.h b/libp2p/RLPXSocket.h new file mode 100644 index 000000000..389418c76 --- /dev/null +++ b/libp2p/RLPXSocket.h @@ -0,0 +1,56 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum 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. + + cpp-ethereum 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 cpp-ethereum. If not, see . + */ +/** @file RLPXSocket.h + * @author Alex Leverington + * @date 2015 + */ + +#pragma once + +#include "Common.h" + +namespace dev +{ +namespace p2p +{ + +/** + * @brief Shared pointer wrapper for ASIO TCP socket. + * + * Thread Safety + * Distinct Objects: Safe. + * Shared objects: Unsafe. + * * an instance method must not be called concurrently + */ +class RLPXSocket: public std::enable_shared_from_this +{ +public: + /// Constructor. Dereferences and takes ownership of _socket. + RLPXSocket(bi::tcp::socket* _socket): m_socket(std::move(*_socket)) {} + ~RLPXSocket() { close(); } + + bool isConnected() const { return m_socket.is_open(); } + void close() { try { boost::system::error_code ec; m_socket.shutdown(bi::tcp::socket::shutdown_both, ec); if (m_socket.is_open()) m_socket.close(); } catch (...){} } + bi::tcp::endpoint remoteEndpoint() { try { return m_socket.remote_endpoint(); } catch (...){ return bi::tcp::endpoint(); } } + bi::tcp::socket& ref() { return m_socket; } + +protected: + bi::tcp::socket m_socket; +}; + +} +} \ No newline at end of file diff --git a/libp2p/RLPxHandshake.cpp b/libp2p/RLPxHandshake.cpp index 8caf6e4f3..47604eedc 100644 --- a/libp2p/RLPxHandshake.cpp +++ b/libp2p/RLPxHandshake.cpp @@ -179,7 +179,7 @@ void RLPXHandshake::transition(boost::system::error_code _ech) /// This pointer will be freed if there is an error otherwise /// it will be passed to Host which will take ownership. - m_io = new RLPXFrameIO(*this); + m_io = new RLPXFrameCoder(*this); // old packet format // 5 arguments, HelloPacket @@ -200,7 +200,7 @@ void RLPXHandshake::transition(boost::system::error_code _ech) } else if (m_nextState == ReadHello) { - // Authenticate and decrypt initial hello frame with initial RLPXFrameIO + // Authenticate and decrypt initial hello frame with initial RLPXFrameCoder // and request m_host to start session. m_nextState = StartSession; @@ -269,7 +269,7 @@ void RLPXHandshake::transition(boost::system::error_code _ech) try { RLP rlp(frame.cropped(1), RLP::ThrowOnFail | RLP::FailIfTooSmall); - m_host->startPeerSession(m_remote, rlp, m_io, m_socket->remoteEndpoint()); + m_host->startPeerSession(m_remote, rlp, m_io, m_socket); } catch (std::exception const& _e) { diff --git a/libp2p/RLPxHandshake.h b/libp2p/RLPxHandshake.h index 47f6afb57..6ed0819c6 100644 --- a/libp2p/RLPxHandshake.h +++ b/libp2p/RLPxHandshake.h @@ -25,7 +25,8 @@ #include #include #include -#include "RLPxFrameIO.h" +#include "RLPXSocket.h" +#include "RLPXFrameCoder.h" #include "Common.h" namespace ba = boost::asio; namespace bi = boost::asio::ip; @@ -36,7 +37,7 @@ namespace p2p { /** - * @brief Setup inbound or outbound connection for communication over RLPXFrameIO. + * @brief Setup inbound or outbound connection for communication over RLPXFrameCoder. * RLPx Spec: https://github.com/ethereum/devp2p/blob/master/rlpx.md#encrypted-handshake * * @todo Implement StartSession transition via lambda which is passed to constructor. @@ -47,7 +48,7 @@ namespace p2p */ class RLPXHandshake: public std::enable_shared_from_this { - friend class RLPXFrameIO; + friend class RLPXFrameCoder; /// Sequential states of handshake enum State @@ -122,7 +123,7 @@ protected: /// Used to read and write RLPx encrypted frames for last step of handshake authentication. /// Passed onto Host which will take ownership. - RLPXFrameIO* m_io = nullptr; + RLPXFrameCoder* m_io = nullptr; std::shared_ptr m_socket; ///< Socket. boost::asio::deadline_timer m_idleTimer; ///< Timer which enforces c_timeout. diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 462fea7b1..260ce10ac 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -27,23 +27,24 @@ #include #include #include +#include "RLPxHandshake.h" #include "Host.h" #include "Capability.h" using namespace std; using namespace dev; using namespace dev::p2p; -Session::Session(Host* _s, RLPXFrameIO* _io, std::shared_ptr const& _n, PeerSessionInfo _info): - m_server(_s), +Session::Session(Host* _h, RLPXFrameCoder* _io, std::shared_ptr const& _s, std::shared_ptr const& _n, PeerSessionInfo _info): + m_server(_h), m_io(_io), - m_socket(m_io->socket()), + m_socket(_s), m_peer(_n), m_info(_info), m_ping(chrono::steady_clock::time_point::max()) { m_peer->m_lastDisconnect = NoDisconnect; m_lastReceived = m_connect = chrono::steady_clock::now(); - m_info.socketId = _io->socket().native_handle(); + m_info.socketId = m_socket->ref().native_handle(); } Session::~Session() @@ -59,11 +60,12 @@ Session::~Session() try { - if (m_socket.is_open()) + bi::tcp::socket& socket = m_socket->ref(); + if (socket.is_open()) { boost::system::error_code ec; - m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); - m_socket.close(); + socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); + socket.close(); } } catch (...){} @@ -303,7 +305,7 @@ void Session::send(bytes&& _msg) if (!checkPacket(msg)) clog(NetWarn) << "INVALID PACKET CONSTRUCTED!"; - if (!m_socket.is_open()) + if (!m_socket->ref().is_open()) return; bool doWrite = false; @@ -326,7 +328,7 @@ void Session::write() out = &m_writeQueue[0]; } auto self(shared_from_this()); - ba::async_write(m_socket, ba::buffer(*out), [this, self](boost::system::error_code ec, std::size_t /*length*/) + ba::async_write(m_socket->ref(), ba::buffer(*out), [this, self](boost::system::error_code ec, std::size_t /*length*/) { ThreadContext tc(info().id.abridged()); ThreadContext tc2(info().clientVersion); @@ -352,13 +354,14 @@ void Session::drop(DisconnectReason _reason) { if (m_dropped) return; - if (m_socket.is_open()) + bi::tcp::socket& socket = m_socket->ref(); + if (socket.is_open()) try { - clog(NetConnect) << "Closing " << m_socket.remote_endpoint() << "(" << reasonOf(_reason) << ")"; + clog(NetConnect) << "Closing " << socket.remote_endpoint() << "(" << reasonOf(_reason) << ")"; boost::system::error_code ec; - m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); - m_socket.close(); + socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec); + socket.close(); } catch (...) {} @@ -379,7 +382,7 @@ void Session::disconnect(DisconnectReason _reason) m_peer->endpoint, // TODO: may not be 100% accurate m_server->peerCount() ); - if (m_socket.is_open()) + if (m_socket->ref().is_open()) { RLPStream s; prep(s, DisconnectPacket, 1) << (int)_reason; @@ -401,7 +404,7 @@ void Session::doRead() return; auto self(shared_from_this()); - ba::async_read(m_socket, boost::asio::buffer(m_data, h256::size), [this,self](boost::system::error_code ec, std::size_t length) + ba::async_read(m_socket->ref(), boost::asio::buffer(m_data, h256::size), [this,self](boost::system::error_code ec, std::size_t length) { ThreadContext tc(info().id.abridged()); ThreadContext tc2(info().clientVersion); @@ -438,7 +441,7 @@ void Session::doRead() /// read padded frame and mac auto tlen = frameSize + ((16 - (frameSize % 16)) % 16) + h128::size; - ba::async_read(m_socket, boost::asio::buffer(m_data, tlen), [this, self, headerRLP, frameSize, tlen](boost::system::error_code ec, std::size_t length) + ba::async_read(m_socket->ref(), boost::asio::buffer(m_data, tlen), [this, self, headerRLP, frameSize, tlen](boost::system::error_code ec, std::size_t length) { ThreadContext tc(info().id.abridged()); ThreadContext tc2(info().clientVersion); diff --git a/libp2p/Session.h b/libp2p/Session.h index bcbf8022b..08006f890 100644 --- a/libp2p/Session.h +++ b/libp2p/Session.h @@ -33,7 +33,8 @@ #include #include #include -#include "RLPxHandshake.h" +#include "RLPXFrameCoder.h" +#include "RLPXSocket.h" #include "Common.h" namespace dev @@ -54,7 +55,7 @@ class Session: public std::enable_shared_from_this friend class HostCapabilityFace; public: - Session(Host* _server, RLPXFrameIO* _io, std::shared_ptr const& _n, PeerSessionInfo _info); + Session(Host* _server, RLPXFrameCoder* _io, std::shared_ptr const& _s, std::shared_ptr const& _n, PeerSessionInfo _info); virtual ~Session(); void start(); @@ -62,7 +63,7 @@ public: void ping(); - bool isConnected() const { return m_socket.is_open(); } + bool isConnected() const { return m_socket->ref().is_open(); } NodeId id() const; unsigned socketId() const { return m_info.socketId; } @@ -105,8 +106,8 @@ private: Host* m_server; ///< The host that owns us. Never null. - RLPXFrameIO* m_io; ///< Transport over which packets are sent. - bi::tcp::socket& m_socket; ///< Socket for the peer's connection. + RLPXFrameCoder* m_io; ///< Transport over which packets are sent. + std::shared_ptr m_socket; ///< Socket of peer's connection. Mutex x_writeQueue; ///< Mutex for the write queue. std::deque m_writeQueue; ///< The write queue. std::array m_data; ///< Buffer for ingress packet data. From 3e46b869ad9efb98e38106085f6baf8bb621b6cb Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 12 Jun 2015 12:59:52 +0900 Subject: [PATCH 24/40] Allow unlocking of wallets over RPC. --- alethzero/OurWebThreeStubServer.cpp | 2 +- eth/main.cpp | 4 ++-- libethereum/ClientBase.cpp | 17 ++--------------- libweb3jsonrpc/WebThreeStubServer.cpp | 16 +++++++++++----- libweb3jsonrpc/WebThreeStubServer.h | 9 ++++++++- libweb3jsonrpc/WebThreeStubServerBase.h | 1 + libweb3jsonrpc/abstractwebthreestubserver.h | 6 ++++++ libweb3jsonrpc/spec.json | 1 + test/libweb3jsonrpc/webthreestubclient.h | 10 ++++++++++ 9 files changed, 42 insertions(+), 24 deletions(-) diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index 7e9836818..85f930792 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -34,7 +34,7 @@ OurWebThreeStubServer::OurWebThreeStubServer( WebThreeDirect& _web3, Main* _main ): - WebThreeStubServer(_conn, _web3, make_shared(_web3, _main), _main->owned().toVector().toStdVector()), + WebThreeStubServer(_conn, _web3, make_shared(_web3, _main), _main->owned().toVector().toStdVector(), _main->keyManager()), m_main(_main) { } diff --git a/eth/main.cpp b/eth/main.cpp index 47dbae318..cfe000500 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -829,7 +829,7 @@ int main(int argc, char** argv) if (jsonrpc > -1) { jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); - jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){return web3.ethereum();}, getAccountPassword, keyManager), vector())); + jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){return web3.ethereum();}, getAccountPassword, keyManager), vector(), keyManager)); jsonrpcServer->StartListening(); } #endif @@ -973,7 +973,7 @@ int main(int argc, char** argv) if (jsonrpc < 0) jsonrpc = SensibleHttpPort; jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); - jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){return web3.ethereum();}, getAccountPassword, keyManager), vector())); + jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, getAccountPassword, keyManager), vector(), keyManager)); jsonrpcServer->StartListening(); } else if (cmd == "jsonstop") diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index 38e92fcd7..d5bc0dbb9 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -49,30 +49,17 @@ void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, b { prepareForTransaction(); - auto a = toAddress(_secret); - u256 n = postMine().transactionsFrom(a); - cdebug << "submitTx: " << a << "postMine=" << n << "; tq=" << m_tq.maxNonce(a); - Transaction t(_value, _gasPrice, _gas, _dest, _data, _nonce, _secret); m_tq.import(t.rlp()); StructuredLogger::transactionReceived(t.sha3().abridged(), t.sender().abridged()); - cnote << "New transaction " << t << "(maxNonce for sender" << a << "is" << m_tq.maxNonce(a) << ")"; + cnote << "New transaction " << t; } void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) { - prepareForTransaction(); - auto a = toAddress(_secret); - u256 n = postMine().transactionsFrom(a); - cdebug << "submitTx: " << a << "postMine=" << n << "; tq=" << m_tq.maxNonce(a); - n = max(n, m_tq.maxNonce(a)); - Transaction t(_value, _gasPrice, _gas, _dest, _data, n, _secret); - m_tq.import(t.rlp()); - - StructuredLogger::transactionReceived(t.sha3().abridged(), t.sender().abridged()); - cnote << "New transaction " << t << "(maxNonce for sender" << a << "is" << m_tq.maxNonce(a) << ")"; + submitTransaction(_secret, _value, _dest, _data, _gas, _gasPrice, max(postMine().transactionsFrom(a), m_tq.maxNonce(a))); } Address ClientBase::submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice) diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 44f7f521c..eae15cd7e 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -24,18 +24,18 @@ // Make sure boost/asio.hpp is included before windows.h. #include #include - -#include #include +#include +#include #include "WebThreeStubServer.h" - using namespace std; using namespace dev; using namespace dev::eth; -WebThreeStubServer::WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, WebThreeDirect& _web3, shared_ptr const& _ethAccounts, std::vector const& _shhAccounts): +WebThreeStubServer::WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, WebThreeDirect& _web3, shared_ptr const& _ethAccounts, std::vector const& _shhAccounts, KeyManager& _keyMan): WebThreeStubServerBase(_conn, _ethAccounts, _shhAccounts), - m_web3(_web3) + m_web3(_web3), + m_keyMan(_keyMan) { auto path = getDataDir() + "/.web3"; boost::filesystem::create_directories(path); @@ -44,6 +44,12 @@ WebThreeStubServer::WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, ldb::DB::Open(o, path, &m_db); } +bool WebThreeStubServer::eth_notePassword(string const& _password) +{ + m_keyMan.notePassword(_password); + return true; +} + std::string WebThreeStubServer::web3_clientVersion() { return m_web3.clientVersion(); diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index 1eddc22d4..68de1808b 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -33,6 +33,10 @@ namespace dev { class WebThreeDirect; +namespace eth +{ +class KeyManager; +} } /** @@ -41,7 +45,7 @@ class WebThreeDirect; class WebThreeStubServer: public dev::WebThreeStubServerBase, public dev::WebThreeStubDatabaseFace { public: - WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::shared_ptr const& _ethAccounts, std::vector const& _shhAccounts); + WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, dev::WebThreeDirect& _web3, std::shared_ptr const& _ethAccounts, std::vector const& _shhAccounts, dev::eth::KeyManager& _keyMan); virtual std::string web3_clientVersion() override; @@ -54,8 +58,11 @@ private: virtual std::string get(std::string const& _name, std::string const& _key) override; virtual void put(std::string const& _name, std::string const& _key, std::string const& _value) override; + virtual bool eth_notePassword(std::string const& _password); + private: dev::WebThreeDirect& m_web3; + dev::eth::KeyManager& m_keyMan; leveldb::ReadOptions m_readOptions; leveldb::WriteOptions m_writeOptions; leveldb::DB* m_db; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index ec24cb08d..07d1d6827 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -122,6 +122,7 @@ public: virtual std::string eth_signTransaction(Json::Value const& _transaction); virtual Json::Value eth_inspectTransaction(std::string const& _rlp); virtual bool eth_injectTransaction(std::string const& _rlp); + virtual bool eth_notePassword(std::string const&) { return false; } virtual bool db_put(std::string const& _name, std::string const& _key, std::string const& _value); virtual std::string db_get(std::string const& _name, std::string const& _key); diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index 522d418c1..2f5764197 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -64,6 +64,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(jsonrpc::Procedure("eth_signTransaction", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_signTransactionI); this->bindAndAddMethod(jsonrpc::Procedure("eth_inspectTransaction", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_inspectTransactionI); this->bindAndAddMethod(jsonrpc::Procedure("eth_injectTransaction", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_injectTransactionI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_notePassword", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_notePasswordI); this->bindAndAddMethod(jsonrpc::Procedure("db_put", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_putI); this->bindAndAddMethod(jsonrpc::Procedure("db_get", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::db_getI); this->bindAndAddMethod(jsonrpc::Procedure("shh_post", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::shh_postI); @@ -301,6 +302,10 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServereth_injectTransaction(request[0u].asString()); } + inline virtual void eth_notePasswordI(const Json::Value &request, Json::Value &response) + { + response = this->eth_notePassword(request[0u].asString()); + } inline virtual void db_putI(const Json::Value &request, Json::Value &response) { response = this->db_put(request[0u].asString(), request[1u].asString(), request[2u].asString()); @@ -398,6 +403,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerCallMethod("eth_notePassword",p); + if (result.isBool()) + return result.asBool(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } bool db_put(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException) { Json::Value p; From 6b80953aa3bfa4423f3e5f950474e12142169890 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 12 Jun 2015 10:30:44 +0200 Subject: [PATCH 25/40] State management in EthereumHost, better sync progress reporting. Invariants checking --- alethzero/Main.ui | 9 ++- alethzero/MainWin.cpp | 13 +++- libethereum/Client.cpp | 4 +- libethereum/Client.h | 2 +- libethereum/CommonNet.h | 25 +++++--- libethereum/DownloadMan.h | 5 -- libethereum/EthereumHost.cpp | 113 +++++++++++++++++++++++++---------- libethereum/EthereumHost.h | 32 ++++++---- 8 files changed, 138 insertions(+), 65 deletions(-) diff --git a/alethzero/Main.ui b/alethzero/Main.ui index efb6256af..f798437e6 100644 --- a/alethzero/Main.ui +++ b/alethzero/Main.ui @@ -44,7 +44,14 @@ 0 bytes used - + + + + + + + + diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 4d96b77ff..a2abb1068 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -198,6 +198,7 @@ Main::Main(QWidget *parent) : statusBar()->addPermanentWidget(ui->balance); statusBar()->addPermanentWidget(ui->peerCount); statusBar()->addPermanentWidget(ui->mineStatus); + statusBar()->addPermanentWidget(ui->syncStatus); statusBar()->addPermanentWidget(ui->chainStatus); statusBar()->addPermanentWidget(ui->blockCount); @@ -1245,9 +1246,15 @@ void Main::refreshBlockCount() { auto d = ethereum()->blockChain().details(); BlockQueueStatus b = ethereum()->blockQueueStatus(); - HashChainStatus h = ethereum()->hashChainStatus(); - ui->chainStatus->setText(QString("%10/%11%12 hashes %3 importing %4 ready %5 verifying %6 unverified %7 future %8 unknown %9 bad %1 #%2") - .arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet").arg(d.number).arg(b.importing).arg(b.verified).arg(b.verifying).arg(b.unverified).arg(b.future).arg(b.unknown).arg(b.bad).arg(h.received).arg(h.estimated ? "~" : "").arg(h.total)); + SyncStatus sync = ethereum()->syncStatus(); + QString syncStatus = EthereumHost::stateName(sync.state); + if (sync.state == SyncState::HashesParallel || sync.state == SyncState::HashesSingle) + syncStatus += QString(": %1/%2%3").arg(sync.hashesReceived).arg(sync.hashesEstimated ? "~" : "").arg(sync.hashesTotal); + if (sync.state == SyncState::Blocks || sync.state == SyncState::NewBlocks) + syncStatus += QString(": %1/%2").arg(sync.blocksReceived).arg(sync.blocksTotal); + ui->syncStatus->setText(syncStatus); + ui->chainStatus->setText(QString("%3 importing %4 ready %5 verifying %6 unverified %7 future %8 unknown %9 bad %1 #%2") + .arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet").arg(d.number).arg(b.importing).arg(b.verified).arg(b.verifying).arg(b.unverified).arg(b.future).arg(b.unknown).arg(b.bad)); } void Main::on_turboMining_triggered() diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index d1ede38ac..23e4f86c8 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -904,8 +904,8 @@ void Client::flushTransactions() doWork(); } -HashChainStatus Client::hashChainStatus() const +SyncStatus Client::syncStatus() const { auto h = m_host.lock(); - return h ? h->status() : HashChainStatus { 0, 0, false }; + return h ? h->status() : SyncStatus(); } diff --git a/libethereum/Client.h b/libethereum/Client.h index cba93290b..5cae50ed0 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -157,7 +157,7 @@ public: /// Get some information on the block queue. BlockQueueStatus blockQueueStatus() const { return m_bq.status(); } /// Get some information on the block queue. - HashChainStatus hashChainStatus() const; + SyncStatus syncStatus() const; /// Get the block queue. BlockQueue const& blockQueue() const { return m_bq; } diff --git a/libethereum/CommonNet.h b/libethereum/CommonNet.h index 2eb2d77c8..b960c8f3f 100644 --- a/libethereum/CommonNet.h +++ b/libethereum/CommonNet.h @@ -77,18 +77,27 @@ enum class Asking Nothing }; -enum class Syncing +enum class SyncState { - Waiting, - Executing, - Done + Idle, ///< Initial chain sync complete. Waiting for new packets + WaitingQueue, ///< Block downloading paused. Waiting for block queue to process blocks and free space + HashesNegotiate, ///< Waiting for first hashes to arrive + HashesSingle, ///< Locked on and downloading hashes from a single peer + HashesParallel, ///< Downloading hashes from multiple peers over + Blocks, ///< Downloading blocks + NewBlocks, ///< Downloading blocks learned from NewHashes packet + + Size /// Must be kept last }; -struct HashChainStatus +struct SyncStatus { - unsigned total; - unsigned received; - bool estimated; + SyncState state = SyncState::Idle; + unsigned hashesTotal = 0; + unsigned hashesReceived = 0; + bool hashesEstimated = false; + unsigned blocksTotal = 0; + unsigned blocksReceived = 0; }; } diff --git a/libethereum/DownloadMan.h b/libethereum/DownloadMan.h index 0c27e84ea..ac99e1d36 100644 --- a/libethereum/DownloadMan.h +++ b/libethereum/DownloadMan.h @@ -253,11 +253,6 @@ public: return m_got.full(); } - unsigned gotCount() const - { - return m_got.size(); - } - size_t chainSize() const { ReadGuard l(m_lock); return m_chainCount; } size_t chainEmpty() const { ReadGuard l(m_lock); return m_chainCount == 0; } void foreachSub(std::function const& _f) const { ReadGuard l(x_subs); for(auto i: m_subs) _f(*i); } diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 4609fddb6..661f34b11 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -41,6 +41,8 @@ using namespace p2p; unsigned const EthereumHost::c_oldProtocolVersion = 60; //TODO: remove this once v61+ is common unsigned const c_chainReorgSize = 30000; +char const* const EthereumHost::s_stateNames[static_cast(SyncState::Size)] = {"Idle", "WaitingQueue", "HashesNegotiate", "HashesSingle", "HashesParallel", "Blocks", "NewBlocks" }; + EthereumHost::EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQueue& _bq, u256 _networkId): HostCapability(), Worker ("ethsync"), @@ -49,6 +51,7 @@ EthereumHost::EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQu m_bq (_bq), m_networkId (_networkId) { + setState(SyncState::HashesNegotiate); m_latestBlockSent = _ch.currentHash(); m_hashMan.reset(m_chain.number() + 1); m_bqRoomAvailable = m_bq.onRoomAvailable([this](){ m_continueSync = true; }); @@ -79,9 +82,7 @@ void EthereumHost::reset() foreachPeer([](EthereumPeer* _p) { _p->abortSync(); }); m_man.resetToChain(h256s()); m_hashMan.reset(m_chain.number() + 1); - m_needSyncBlocks = true; - m_needSyncHashes = true; - m_syncingNewHashes = false; + setState(SyncState::HashesNegotiate); m_syncingLatestHash = h256(); m_syncingTotalDifficulty = 0; m_latestBlockSent = h256(); @@ -91,10 +92,18 @@ void EthereumHost::reset() void EthereumHost::resetSyncTo(h256 const& _h) { - m_needSyncHashes = true; - m_needSyncBlocks = true; + setState(SyncState::HashesNegotiate); m_syncingLatestHash = _h; - m_syncingNewHashes = false; +} + + +void EthereumHost::setState(SyncState _s) +{ + if (m_state != _s) + { + clog(NetAllDetail) << "SyncState changed from " << stateName(m_state) << " to " << stateName(_s); + m_state = _s; + } } void EthereumHost::doWork() @@ -255,6 +264,7 @@ void EthereumHost::maintainBlocks(h256 const& _currentHash) void EthereumHost::onPeerStatus(EthereumPeer* _peer) { RecursiveGuard l(x_sync); + DEV_INVARIANT_CHECK; if (_peer->m_genesisHash != m_chain.genesisHash()) _peer->disable("Invalid genesis hash"); else if (_peer->m_protocolVersion != protocolVersion() && _peer->m_protocolVersion != c_oldProtocolVersion) @@ -274,13 +284,14 @@ void EthereumHost::onPeerStatus(EthereumPeer* _peer) _peer->m_expectedHashes = (unsigned)_peer->m_latestBlockNumber - m_chain.number(); if (_peer->m_expectedHashes > estimatedHashes) _peer->disable("Too many hashes"); - else if (m_needSyncHashes && m_hashMan.chainSize() < _peer->m_expectedHashes) + else if (needHashes() && m_hashMan.chainSize() < _peer->m_expectedHashes) m_hashMan.resetToRange(m_chain.number() + 1, _peer->m_expectedHashes); } else _peer->m_expectedHashes = estimatedHashes; continueSync(_peer); } + DEV_INVARIANT_CHECK; } unsigned EthereumHost::estimateHashes() @@ -309,6 +320,7 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool _complete) { + DEV_INVARIANT_CHECK; if (_hashes.empty()) { _peer->m_hashSub.doneFetch(); @@ -376,8 +388,8 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool if (_complete) { clog(NetMessageSummary) << "Start new blocks download..."; - m_needSyncBlocks = true; - m_syncingNewHashes = true; + m_syncingLatestHash = h256(); + setState(SyncState::NewBlocks); m_man.resetToChain(m_hashes); m_hashes.clear(); m_hashMan.reset(m_chain.number() + 1); @@ -386,40 +398,41 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool else if (syncByNumber && m_hashMan.isComplete()) { // Done our chain-get. - m_needSyncHashes = false; clog(NetNote) << "Hashes download complete."; - // 1/100th for each useful block hash. - _peer->addRating(m_man.chainSize() / 100); //TODO: what about other peers? - m_hashMan.reset(m_chain.number() + 1); - continueSync(); + onPeerDoneHashes(_peer, false); } else if (m_hashes.size() > _peer->m_expectedHashes) { _peer->disable("Too many hashes"); m_hashes.clear(); m_syncingLatestHash = h256(); + setState(SyncState::HashesNegotiate); continueSync(); ///Try with some other peer, keep the chain } else continueSync(_peer); /// Grab next hashes + DEV_INVARIANT_CHECK; } void EthereumHost::onPeerDoneHashes(EthereumPeer* _peer, bool _localChain) { assert(_peer->m_asking == Asking::Nothing); - m_needSyncHashes = false; + m_syncingLatestHash = h256(); + setState(SyncState::Blocks); if (_peer->m_protocolVersion != protocolVersion() || _localChain) { m_man.resetToChain(m_hashes); - m_hashes.clear(); - m_hashMan.reset(m_chain.number() + 1); + _peer->addRating(m_man.chainSize() / 100); //TODO: what about other peers? } + m_hashMan.reset(m_chain.number() + 1); + m_hashes.clear(); continueSync(); } void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) { RecursiveGuard l(x_sync); + DEV_INVARIANT_CHECK; _peer->setAsking(Asking::Nothing); unsigned itemCount = _r.itemCount(); clog(NetMessageSummary) << "Blocks (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreBlocks"); @@ -484,19 +497,21 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) clog(NetMessageSummary) << dec << success << "imported OK," << unknown << "with unknown parents," << future << "with future timestamps," << got << " already known," << repeated << " repeats received."; - if (m_syncingNewHashes && unknown > 0) + if (m_state == SyncState::NewBlocks && unknown > 0) { _peer->m_latestHash = lastUnknown; resetSyncTo(lastUnknown); } continueSync(_peer); + DEV_INVARIANT_CHECK; } void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) { RecursiveGuard l(x_sync); - if (isSyncing_UNSAFE() || _peer->isConversing()) + DEV_INVARIANT_CHECK; + if (isSyncing() || _peer->isConversing()) { clog(NetMessageSummary) << "Ignoring new hashes since we're already downloading."; return; @@ -504,12 +519,14 @@ void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) clog(NetNote) << "New block hash discovered: syncing without help."; _peer->m_syncHashNumber = 0; onPeerHashes(_peer, _hashes, true); + DEV_INVARIANT_CHECK; } void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) { RecursiveGuard l(x_sync); - if ((isSyncing_UNSAFE() || _peer->isConversing()) && !m_syncingNewHashes) + DEV_INVARIANT_CHECK; + if ((isSyncing() || _peer->isConversing()) && m_state != SyncState::NewBlocks) { clog(NetMessageSummary) << "Ignoring new blocks since we're already downloading."; return; @@ -563,6 +580,7 @@ void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) if (sync) continueSync(); } + DEV_INVARIANT_CHECK; } void EthereumHost::onPeerTransactions(EthereumPeer* _peer, RLP const& _r) @@ -607,6 +625,8 @@ void EthereumHost::onPeerAborting(EthereumPeer* _peer) void EthereumHost::continueSync() { + if (m_state == SyncState::WaitingQueue) + setState(m_lastActiveState); clog(NetAllDetail) << "Continuing sync for all peers"; foreachPeer([&](EthereumPeer* _p) { @@ -617,10 +637,11 @@ void EthereumHost::continueSync() void EthereumHost::continueSync(EthereumPeer* _peer) { + DEV_INVARIANT_CHECK; assert(_peer->m_asking == Asking::Nothing); bool otherPeerV60Sync = false; bool otherPeerV61Sync = false; - if (m_needSyncHashes) + if (needHashes()) { if (!peerShouldGrabChain(_peer)) { @@ -652,7 +673,7 @@ void EthereumHost::continueSync(EthereumPeer* _peer) } if (_peer->m_protocolVersion == protocolVersion() && !m_hashMan.isComplete()) { - m_syncingV61 = true; + setState(SyncState::HashesParallel); _peer->requestHashes(); /// v61+ and not catching up to a particular hash } else @@ -666,20 +687,19 @@ void EthereumHost::continueSync(EthereumPeer* _peer) if (_peer->m_totalDifficulty >= m_syncingTotalDifficulty) { _peer->requestHashes(m_syncingLatestHash); - m_syncingV61 = false; + setState(SyncState::HashesSingle); m_estimatedHashes = _peer->m_expectedHashes - (_peer->m_protocolVersion == protocolVersion() ? 0 : c_chainReorgSize); } else _peer->setIdle(); } } - else if (m_needSyncBlocks) + else if (needBlocks()) { if (m_man.isComplete()) { // Done our chain-get. - m_needSyncBlocks = false; - m_syncingNewHashes = false; + setState(SyncState::Idle); clog(NetNote) << "Chain download complete."; // 1/100th for each useful block hash. _peer->addRating(m_man.chainSize() / 100); //TODO: what about other peers? @@ -700,6 +720,8 @@ void EthereumHost::continueSync(EthereumPeer* _peer) else if (m_bq.knownFull()) { clog(NetAllDetail) << "Waiting for block queue before downloading blocks"; + m_lastActiveState = m_state; + setState(SyncState::WaitingQueue); _peer->setIdle(); } else @@ -708,6 +730,7 @@ void EthereumHost::continueSync(EthereumPeer* _peer) } else _peer->setIdle(); + DEV_INVARIANT_CHECK; } bool EthereumHost::peerCanHelp(EthereumPeer* _peer) const @@ -754,16 +777,42 @@ bool EthereumHost::peerShouldGrabChain(EthereumPeer* _peer) const } } -bool EthereumHost::isSyncing_UNSAFE() const +bool EthereumHost::isSyncing() const { - return m_needSyncBlocks || m_needSyncHashes; + return m_state != SyncState::Idle; } -HashChainStatus EthereumHost::status() +SyncStatus EthereumHost::status() const { RecursiveGuard l(x_sync); - if (m_syncingV61) - return HashChainStatus { static_cast(m_hashMan.chainSize()), static_cast(m_hashMan.gotCount()), false }; - return HashChainStatus { m_estimatedHashes > 0 ? m_estimatedHashes : 0, static_cast(m_hashes.size()), m_estimatedHashes > 0 }; + SyncStatus res; + res.state = m_state; + if (m_state == SyncState::HashesParallel) + { + res.hashesReceived = m_hashMan.hashesGot().size(); + res.hashesTotal = m_hashMan.chainSize(); + } + else if (m_state == SyncState::HashesSingle) + { + res.hashesTotal = m_estimatedHashes; + res.hashesReceived = static_cast(m_hashes.size()); + res.hashesEstimated = true; + } + else if (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks || m_state == SyncState::WaitingQueue) + { + res.blocksTotal = m_man.chainSize(); + res.blocksReceived = m_man.blocksGot().size(); + } + return res; } + +bool EthereumHost::invariants() const +{ + if (m_state == SyncState::HashesNegotiate && !m_hashes.empty()) + return false; + if (needBlocks() && (m_syncingLatestHash || !m_hashes.empty())) + return false; + + return true; +} diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h index 392e234f3..098d893ee 100644 --- a/libethereum/EthereumHost.h +++ b/libethereum/EthereumHost.h @@ -54,9 +54,10 @@ class BlockQueue; * @warning None of this is thread-safe. You have been warned. * @doWork Syncs to peers and sends new blocks and transactions. */ -class EthereumHost: public p2p::HostCapability, Worker +class EthereumHost: public p2p::HostCapability, Worker, HasInvariants { public: + /// Start server, but don't listen. EthereumHost(BlockChain const& _ch, TransactionQueue& _tq, BlockQueue& _bq, u256 _networkId); @@ -70,7 +71,7 @@ public: void reset(); DownloadMan const& downloadMan() const { return m_man; } - bool isSyncing() const { RecursiveGuard l(x_sync); return isSyncing_UNSAFE(); } + bool isSyncing() const; bool isBanned(p2p::NodeId const& _id) const { return !!m_banned.count(_id); } void noteNewTransactions() { m_newTransactions = true; } @@ -87,17 +88,21 @@ public: DownloadMan& downloadMan() { return m_man; } HashDownloadMan& hashDownloadMan() { return m_hashMan; } BlockChain const& chain() { return m_chain; } - HashChainStatus status(); + SyncStatus status() const; + static char const* stateName(SyncState _s) { return s_stateNames[static_cast(_s)]; } static unsigned const c_oldProtocolVersion; private: + static char const* const s_stateNames[static_cast(SyncState::Size)]; + std::tuple>, std::vector>, std::vector>> randomSelection(unsigned _percent = 25, std::function const& _allow = [](EthereumPeer const*){ return true; }); void foreachPeerPtr(std::function)> const& _f) const; void foreachPeer(std::function const& _f) const; - bool isSyncing_UNSAFE() const; void resetSyncTo(h256 const& _h); + bool needHashes() const { return m_state == SyncState::HashesNegotiate || m_state == SyncState::HashesSingle || m_state == SyncState::HashesParallel; } + bool needBlocks() const { return m_state == SyncState::Blocks || m_state == SyncState::NewBlocks; } /// Sync with the BlockChain. It might contain one of our mined blocks, we might have new candidates from the network. void doWork(); @@ -128,6 +133,9 @@ private: bool peerCanHelp(EthereumPeer* _peer) const; unsigned estimateHashes(); void estimatePeerHashes(EthereumPeer* _peer); + void setState(SyncState _s); + + bool invariants() const override; BlockChain const& m_chain; TransactionQueue& m_tq; ///< Maintains a list of incoming transactions not yet in a block on the blockchain. @@ -148,15 +156,13 @@ private: bool m_newBlocks = false; mutable RecursiveMutex x_sync; - bool m_needSyncHashes = true; ///< Indicates if need to downlad hashes - bool m_needSyncBlocks = true; ///< Indicates if we still need to download some blocks - h256 m_syncingLatestHash; ///< Latest block's hash, as of the current sync. - u256 m_syncingTotalDifficulty; ///< Latest block's total difficulty, as of the current sync. - bool m_syncingNewHashes = false; ///< True if currently downloading hashes received with NewHashes - h256s m_hashes; ///< List of hashes with unknown block numbers. Used for PV60 chain downloading and catching up to a particular unknown - unsigned m_estimatedHashes = 0; ///< Number of estimated hashes for the last peer over PV60. Used for status reporting only. - bool m_syncingV61 = false; ///< True if recent activity was over pv61+. Used for status reporting only. - bool m_continueSync = false; ///< True when the block queue has processed a block; we should restart grabbing blocks. + SyncState m_state = SyncState::Idle; ///< Current sync state + SyncState m_lastActiveState = SyncState::Idle; ///< Saved state before entering waiting queue mode + h256 m_syncingLatestHash; ///< Latest block's hash, as of the current sync. + u256 m_syncingTotalDifficulty; ///< Latest block's total difficulty, as of the current sync. + h256s m_hashes; ///< List of hashes with unknown block numbers. Used for PV60 chain downloading and catching up to a particular unknown + unsigned m_estimatedHashes = 0; ///< Number of estimated hashes for the last peer over PV60. Used for status reporting only. + bool m_continueSync = false; ///< True when the block queue has processed a block; we should restart grabbing blocks. }; } From 20e4fc7b93e547cb7a8e1c57743b951fdfcbc2fb Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 12 Jun 2015 17:33:21 +0900 Subject: [PATCH 26/40] First JSONRPC admin method. --- alethzero/DappLoader.cpp | 1 + alethzero/DappLoader.h | 3 +++ alethzero/MainWin.cpp | 8 ++++++- alethzero/OurWebThreeStubServer.cpp | 15 ++++-------- alethzero/OurWebThreeStubServer.h | 7 +----- eth/main.cpp | 26 ++++++++++++++++----- libdevcore/Base64.cpp | 12 ++++++---- libjsqrc/ethereumjs/lib/web3.js | 12 ++++++++++ libjsqrc/ethereumjs/lib/web3/eth.js | 10 ++++---- libweb3jsonrpc/WebThreeStubServer.cpp | 24 +++++++++++++++++++ libweb3jsonrpc/WebThreeStubServer.h | 13 +++++++++++ libweb3jsonrpc/WebThreeStubServerBase.h | 4 +++- libweb3jsonrpc/abstractwebthreestubserver.h | 6 +++++ libweb3jsonrpc/spec.json | 5 +++- test/libweb3jsonrpc/webthreestubclient.h | 10 ++++++++ 15 files changed, 122 insertions(+), 34 deletions(-) diff --git a/alethzero/DappLoader.cpp b/alethzero/DappLoader.cpp index b2249ae5b..662a1afbc 100644 --- a/alethzero/DappLoader.cpp +++ b/alethzero/DappLoader.cpp @@ -108,6 +108,7 @@ void DappLoader::downloadComplete(QNetworkReply* _reply) //inject web3 js QByteArray content = "\n"); content.append(_reply->readAll()); QString contentType = _reply->header(QNetworkRequest::ContentTypeHeader).toString(); diff --git a/alethzero/DappLoader.h b/alethzero/DappLoader.h index f2d3ee5e5..39176e750 100644 --- a/alethzero/DappLoader.h +++ b/alethzero/DappLoader.h @@ -78,6 +78,8 @@ public: ///@param _uri Page Uri void loadPage(QString const& _uri); + void setSessionKey(std::string const& _s) { m_sessionKey = _s; } + signals: void dappReady(Dapp& _dapp); void pageReady(QByteArray const& _content, QString const& _mimeType, QUrl const& _uri); @@ -99,5 +101,6 @@ private: std::set m_pageUrls; QByteArray m_web3Js; dev::Address m_nameReg; + std::string m_sessionKey; }; diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp index 4d96b77ff..28bcd7ab4 100644 --- a/alethzero/MainWin.cpp +++ b/alethzero/MainWin.cpp @@ -209,7 +209,9 @@ Main::Main(QWidget *parent) : m_webThree.reset(new WebThreeDirect(string("AlethZero/v") + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM), getDataDir(), WithExisting::Trust, {"eth"/*, "shh"*/}, p2p::NetworkPreferences(), network)); m_httpConnector.reset(new jsonrpc::HttpServer(SensibleHttpPort, "", "", dev::SensibleHttpThreads)); - m_server.reset(new OurWebThreeStubServer(*m_httpConnector, *web3(), this)); + auto w3ss = new OurWebThreeStubServer(*m_httpConnector, this); + m_server.reset(w3ss); + auto sessionKey = w3ss->newSession({true}); connect(&*m_server, SIGNAL(onNewId(QString)), SLOT(addNewId(QString))); m_server->setIdentities(keysAsVector(owned())); m_server->StartListening(); @@ -226,12 +228,16 @@ Main::Main(QWidget *parent) : m_dappHost.reset(new DappHost(8081)); m_dappLoader = new DappLoader(this, web3(), getNameReg()); + m_dappLoader->setSessionKey(sessionKey); connect(m_dappLoader, &DappLoader::dappReady, this, &Main::dappLoaded); connect(m_dappLoader, &DappLoader::pageReady, this, &Main::pageLoaded); // ui->webView->page()->settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true); // QWebEngineInspector* inspector = new QWebEngineInspector(); // inspector->setPage(page); setBeneficiary(*m_keyManager.accounts().begin()); + + ethereum()->setDefault(LatestBlock); + readSettings(); m_transact = new Transact(this, this); diff --git a/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index 85f930792..39ab69a19 100644 --- a/alethzero/OurWebThreeStubServer.cpp +++ b/alethzero/OurWebThreeStubServer.cpp @@ -31,10 +31,9 @@ using namespace dev::eth; OurWebThreeStubServer::OurWebThreeStubServer( jsonrpc::AbstractServerConnector& _conn, - WebThreeDirect& _web3, Main* _main ): - WebThreeStubServer(_conn, _web3, make_shared(_web3, _main), _main->owned().toVector().toStdVector(), _main->keyManager()), + WebThreeStubServer(_conn, *_main->web3(), make_shared(_main), _main->owned().toVector().toStdVector(), _main->keyManager()), m_main(_main) { } @@ -46,12 +45,8 @@ string OurWebThreeStubServer::shh_newIdentity() return toJS(kp.pub()); } -OurAccountHolder::OurAccountHolder( - WebThreeDirect& _web3, - Main* _main -): - AccountHolder([=](){ return m_web3->ethereum(); }), - m_web3(&_web3), +OurAccountHolder::OurAccountHolder(Main* _main): + AccountHolder([=](){ return _main->ethereum(); }), m_main(_main) { connect(_main, SIGNAL(poll()), this, SLOT(doValidations())); @@ -135,7 +130,7 @@ void OurAccountHolder::doValidations() else // sign and submit. if (Secret s = m_main->retrieveSecret(t.from)) - m_web3->ethereum()->submitTransaction(s, t); + m_main->ethereum()->submitTransaction(s, t); } } @@ -155,7 +150,7 @@ bool OurAccountHolder::validateTransaction(TransactionSkeleton const& _t, bool _ return showCreationNotice(_t, _toProxy); } - h256 contractCodeHash = m_web3->ethereum()->postState().codeHash(_t.to); + h256 contractCodeHash = m_main->ethereum()->postState().codeHash(_t.to); if (contractCodeHash == EmptySHA3) { // recipient has no code - nothing special about this transaction, show basic value transfer info diff --git a/alethzero/OurWebThreeStubServer.h b/alethzero/OurWebThreeStubServer.h index a07188b2d..43985b640 100644 --- a/alethzero/OurWebThreeStubServer.h +++ b/alethzero/OurWebThreeStubServer.h @@ -34,10 +34,7 @@ class OurAccountHolder: public QObject, public dev::eth::AccountHolder Q_OBJECT public: - OurAccountHolder( - dev::WebThreeDirect& _web3, - Main* _main - ); + OurAccountHolder(Main* _main); public slots: void doValidations(); @@ -59,7 +56,6 @@ private: std::queue m_queued; dev::Mutex x_queued; - dev::WebThreeDirect* m_web3; Main* m_main; }; @@ -70,7 +66,6 @@ class OurWebThreeStubServer: public QObject, public WebThreeStubServer public: OurWebThreeStubServer( jsonrpc::AbstractServerConnector& _conn, - dev::WebThreeDirect& _web3, Main* main ); diff --git a/eth/main.cpp b/eth/main.cpp index cfe000500..259a993c9 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -126,6 +126,7 @@ void help() #if ETH_JSONRPC || !ETH_TRUE << " -j,--json-rpc Enable JSON-RPC server (default: off)." << endl << " --json-rpc-port Specify JSON-RPC server port (implies '-j', default: " << SensibleHttpPort << ")." << endl + << " --admin Specify admin session key for JSON-RPC (default: auto-generated and printed at startup)." << endl #endif << " -K,--kill First kill the blockchain." << endl << " -R,--rebuild Rebuild the blockchain from the existing database." << endl @@ -288,6 +289,7 @@ int main(int argc, char** argv) #if ETH_JSONRPC int jsonrpc = -1; #endif + string jsonAdmin; bool upnp = true; WithExisting killChain = WithExisting::Trust; bool jit = false; @@ -599,6 +601,8 @@ int main(int argc, char** argv) jsonrpc = jsonrpc == -1 ? SensibleHttpPort : jsonrpc; else if (arg == "--json-rpc-port" && i + 1 < argc) jsonrpc = atoi(argv[++i]); + else if (arg == "--json-admin" && i + 1 < argc) + jsonAdmin = argv[++i]; #endif #if ETH_JSCONSOLE else if (arg == "--console") @@ -817,12 +821,6 @@ int main(int argc, char** argv) else cout << "Networking disabled. To start, use netstart or pass -b or a remote host." << endl; - if (bootstrap) - for (auto const& i: Host::pocHosts()) - web3.requirePeer(i.first, i.second); - if (!remoteHost.empty()) - web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort)); - #if ETH_JSONRPC || !ETH_TRUE shared_ptr jsonrpcServer; unique_ptr jsonrpcConnector; @@ -831,9 +829,20 @@ int main(int argc, char** argv) jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){return web3.ethereum();}, getAccountPassword, keyManager), vector(), keyManager)); jsonrpcServer->StartListening(); + if (jsonAdmin.empty()) + jsonAdmin = jsonrpcServer->newSession(SessionPermissions{true}); + else + jsonrpcServer->addSession(jsonAdmin, SessionPermissions{true}); + cout << "JSONRPC Admin Session Key: " << jsonAdmin << endl; } #endif + if (bootstrap) + for (auto const& i: Host::pocHosts()) + web3.requirePeer(i.first, i.second); + if (!remoteHost.empty()) + web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort)); + signal(SIGABRT, &sighandler); signal(SIGTERM, &sighandler); signal(SIGINT, &sighandler); @@ -975,6 +984,11 @@ int main(int argc, char** argv) jsonrpcConnector = unique_ptr(new jsonrpc::HttpServer(jsonrpc, "", "", SensibleHttpThreads)); jsonrpcServer = shared_ptr(new WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, getAccountPassword, keyManager), vector(), keyManager)); jsonrpcServer->StartListening(); + if (jsonAdmin.empty()) + jsonAdmin = jsonrpcServer->newSession(SessionPermissions{true}); + else + jsonrpcServer->addSession(jsonAdmin, SessionPermissions{true}); + cout << "JSONRPC Admin Session Key: " << jsonAdmin << endl; } else if (cmd == "jsonstop") { diff --git a/libdevcore/Base64.cpp b/libdevcore/Base64.cpp index e36f8a18a..f97c82156 100644 --- a/libdevcore/Base64.cpp +++ b/libdevcore/Base64.cpp @@ -29,11 +29,13 @@ #include "Base64.h" using namespace dev; -static inline bool is_base64(byte c) { +static inline bool is_base64(byte c) +{ return (isalnum(c) || (c == '+') || (c == '/')); } -static inline byte find_base64_char_index(byte c) { +static inline byte find_base64_char_index(byte c) +{ if ('A' <= c && c <= 'Z') return c - 'A'; else if ('a' <= c && c <= 'z') return c - 'a' + 1 + find_base64_char_index('Z'); else if ('0' <= c && c <= '9') return c - '0' + 1 + find_base64_char_index('z'); @@ -42,7 +44,8 @@ static inline byte find_base64_char_index(byte c) { else return 1 + find_base64_char_index('/'); } -std::string dev::toBase64(bytesConstRef _in) { +std::string dev::toBase64(bytesConstRef _in) +{ static const char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" @@ -91,7 +94,8 @@ std::string dev::toBase64(bytesConstRef _in) { return ret; } -bytes dev::fromBase64(std::string const& encoded_string) { +bytes dev::fromBase64(std::string const& encoded_string) +{ auto in_len = encoded_string.size(); int i = 0; int j = 0; diff --git a/libjsqrc/ethereumjs/lib/web3.js b/libjsqrc/ethereumjs/lib/web3.js index 021d896e6..982f75d9e 100644 --- a/libjsqrc/ethereumjs/lib/web3.js +++ b/libjsqrc/ethereumjs/lib/web3.js @@ -158,5 +158,17 @@ setupProperties(web3.eth, eth.properties); setupMethods(web3.db, db.methods); setupMethods(web3.shh, shh.methods); +web3.admin = {}; +web3.admin.setSessionKey = function(s) { web3.admin.sessionKey = s; }; + +var blockQueueStatus = new Method({ + name: 'blockQueueStatus', + call: 'admin_eth_blockQueueStatus', + params: 1, + inputFormatter: [function() { return web3.sessionKey; }] +}); + +setupMethods(web3.admin, [blockQueueStatus]); + module.exports = web3; diff --git a/libjsqrc/ethereumjs/lib/web3/eth.js b/libjsqrc/ethereumjs/lib/web3/eth.js index 87a2b290c..23297f1f0 100644 --- a/libjsqrc/ethereumjs/lib/web3/eth.js +++ b/libjsqrc/ethereumjs/lib/web3/eth.js @@ -77,11 +77,11 @@ var uncleCountCall = function (args) { /// @returns an array of objects describing web3.eth api methods var getBalance = new Method({ - name: 'getBalance', - call: 'eth_getBalance', - params: 2, - inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter], - outputFormatter: formatters.outputBigNumberFormatter + name: 'getBalance', + call: 'eth_getBalance', + params: 2, + inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter], + outputFormatter: formatters.outputBigNumberFormatter }); var getStorageAt = new Method({ diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index eae15cd7e..1bef71b59 100644 --- a/libweb3jsonrpc/WebThreeStubServer.cpp +++ b/libweb3jsonrpc/WebThreeStubServer.cpp @@ -44,12 +44,36 @@ WebThreeStubServer::WebThreeStubServer(jsonrpc::AbstractServerConnector& _conn, ldb::DB::Open(o, path, &m_db); } +std::string WebThreeStubServer::newSession(SessionPermissions const& _p) +{ + std::string s = toBase64(h64::random().ref()); + m_sessions[s] = _p; + return s; +} + bool WebThreeStubServer::eth_notePassword(string const& _password) { m_keyMan.notePassword(_password); return true; } +Json::Value WebThreeStubServer::admin_eth_blockQueueStatus(string const& _session) +{ + Json::Value ret; + if (isAdmin(_session)) + { + BlockQueueStatus bqs = m_web3.ethereum()->blockQueue().status(); + ret["importing"] = (int)bqs.importing; + ret["verified"] = (int)bqs.verified; + ret["verifying"] = (int)bqs.verifying; + ret["unverified"] = (int)bqs.unverified; + ret["future"] = (int)bqs.future; + ret["unknown"] = (int)bqs.unknown; + ret["bad"] = (int)bqs.bad; + } + return ret; +} + std::string WebThreeStubServer::web3_clientVersion() { return m_web3.clientVersion(); diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index 68de1808b..4a9dd1911 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -39,6 +39,11 @@ class KeyManager; } } +struct SessionPermissions +{ + bool admin; +}; + /** * @brief JSON-RPC api implementation for WebThreeDirect */ @@ -49,7 +54,12 @@ public: virtual std::string web3_clientVersion() override; + std::string newSession(SessionPermissions const& _p); + void addSession(std::string const& _session, SessionPermissions const& _p) { m_sessions[_session] = _p; } + private: + bool isAdmin(std::string const& _session) const { auto it = m_sessions.find(_session); return it != m_sessions.end() && it->second.admin; } + virtual dev::eth::Interface* client() override; virtual std::shared_ptr face() override; virtual dev::WebThreeNetworkFace* network() override; @@ -59,6 +69,7 @@ private: virtual void put(std::string const& _name, std::string const& _key, std::string const& _value) override; virtual bool eth_notePassword(std::string const& _password); + virtual Json::Value admin_eth_blockQueueStatus(std::string const& _session); private: dev::WebThreeDirect& m_web3; @@ -66,4 +77,6 @@ private: leveldb::ReadOptions m_readOptions; leveldb::WriteOptions m_writeOptions; leveldb::DB* m_db; + + std::unordered_map m_sessions; }; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index 07d1d6827..93a54cce7 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -136,7 +136,9 @@ public: virtual bool shh_uninstallFilter(std::string const& _filterId); virtual Json::Value shh_getFilterChanges(std::string const& _filterId); virtual Json::Value shh_getMessages(std::string const& _filterId); - + + virtual Json::Value admin_eth_blockQueueStatus(std::string const&) { return Json::Value(); } + void setIdentities(std::vector const& _ids); std::map const& ids() const { return m_shhIds; } diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index 2f5764197..675a03614 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -76,6 +76,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(jsonrpc::Procedure("shh_uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_uninstallFilterI); this->bindAndAddMethod(jsonrpc::Procedure("shh_getFilterChanges", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_getFilterChangesI); this->bindAndAddMethod(jsonrpc::Procedure("shh_getMessages", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_getMessagesI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_blockQueueStatus", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_blockQueueStatusI); } inline virtual void web3_sha3I(const Json::Value &request, Json::Value &response) @@ -351,6 +352,10 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServershh_getMessages(request[0u].asString()); } + inline virtual void admin_eth_blockQueueStatusI(const Json::Value &request, Json::Value &response) + { + response = this->admin_eth_blockQueueStatus(request[0u].asString()); + } virtual std::string web3_sha3(const std::string& param1) = 0; virtual std::string web3_clientVersion() = 0; virtual std::string net_version() = 0; @@ -415,6 +420,7 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerCallMethod("admin_eth_blockQueueStatus",p); + if (result.isObject()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } }; #endif //JSONRPC_CPP_STUB_WEBTHREESTUBCLIENT_H_ From 35b786be2479f23c3b1388cead3eb3d4e38bf45b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 12 Jun 2015 10:41:06 +0200 Subject: [PATCH 27/40] OS stack memory offloading for VM execution. --- libethereum/ExtVM.cpp | 48 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/libethereum/ExtVM.cpp b/libethereum/ExtVM.cpp index 782d4d79c..d9ff738ed 100644 --- a/libethereum/ExtVM.cpp +++ b/libethereum/ExtVM.cpp @@ -20,18 +20,58 @@ */ #include "ExtVM.h" - +#include +#include #include "Executive.h" -using namespace std; + using namespace dev; using namespace dev::eth; +namespace +{ +static unsigned const c_depthLimit = 1024; +static size_t const c_singleExecutionStackSize = 8 * 1024; +static size_t const c_defaultStackSize = 512 * 1024; +static unsigned const c_offloadPoint = c_defaultStackSize / c_singleExecutionStackSize; + +void goOnOffloadedStack(Executive& _e, OnOpFunc const& _onOp) +{ + cnote << "CALL OFFLOADING: offloading point " << c_offloadPoint; + boost::thread::attributes attrs; + attrs.set_stack_size((c_depthLimit - c_offloadPoint) * c_singleExecutionStackSize); + + std::exception_ptr exception; + boost::thread{attrs, [&]{ + cnote << "OFFLOADING thread"; + try + { + _e.go(_onOp); + } + catch (...) + { + cnote << "!!!!!!!!!!! exception in offloading!!!!!!!!!!!!"; + exception = std::current_exception(); + } + }}.join(); + if (exception) + std::rethrow_exception(exception); +} + +void go(unsigned _depth, Executive& _e, OnOpFunc const& _onOp) +{ + if (_depth == c_offloadPoint) + goOnOffloadedStack(_e, _onOp); + else + _e.go(_onOp); +} +} + bool ExtVM::call(CallParameters& _p) { Executive e(m_s, lastHashes, depth + 1); if (!e.call(_p, gasPrice, origin)) { - e.go(_p.onOp); + go(depth, e, _p.onOp); e.accrueSubState(sub); } _p.gas = e.gas(); @@ -47,7 +87,7 @@ h160 ExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _code, OnOpFunc Executive e(m_s, lastHashes, depth + 1); if (!e.create(myAddress, _endowment, gasPrice, io_gas, _code, origin)) { - e.go(_onOp); + go(depth, e, _onOp); e.accrueSubState(sub); } io_gas = e.gas(); From 1b4745c95b00d364fedd2afbd8b3ba181b569e67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 12 Jun 2015 10:42:01 +0200 Subject: [PATCH 28/40] Do not set stack memory limit on OSX. --- cmake/EthCompilerSettings.cmake | 5 ----- 1 file changed, 5 deletions(-) diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake index d21a3d4b1..53535a489 100644 --- a/cmake/EthCompilerSettings.cmake +++ b/cmake/EthCompilerSettings.cmake @@ -55,11 +55,6 @@ else () message(WARNING "Your compiler is not tested, if you run into any issues, we'd welcome any patches.") endif () -# Set stack memory limits -if (APPLE) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-stack_size,1000000") -endif() - if (PROFILING AND (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"))) set(CMAKE_CXX_FLAGS "-g ${CMAKE_CXX_FLAGS}") set(CMAKE_C_FLAGS "-g ${CMAKE_C_FLAGS}") From 8ccd0bb22967492b9a72ad4f006c2f4f837f1ab5 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 12 Jun 2015 11:02:03 +0200 Subject: [PATCH 29/40] added missing resync guard --- libethereum/EthereumHost.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index 661f34b11..c5cc1a6e0 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -128,6 +128,7 @@ void EthereumHost::doWork() if (m_continueSync) { m_continueSync = false; + RecursiveGuard l(x_sync); continueSync(); } From 6c45ac6ab10651e11a0b978845a87ce2d6b14a1e Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 12 Jun 2015 11:06:05 +0200 Subject: [PATCH 30/40] Optimize RETURN x 0 to STOP. --- libevmasm/CommonSubexpressionEliminator.cpp | 48 +++++++++++++-------- libsolidity/Compiler.cpp | 5 ++- test/libsolidity/SolidityOptimizer.cpp | 8 ++++ 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/libevmasm/CommonSubexpressionEliminator.cpp b/libevmasm/CommonSubexpressionEliminator.cpp index 2c4742d61..8fb4625a8 100644 --- a/libevmasm/CommonSubexpressionEliminator.cpp +++ b/libevmasm/CommonSubexpressionEliminator.cpp @@ -79,31 +79,43 @@ void CommonSubexpressionEliminator::feedItem(AssemblyItem const& _item, bool _co void CommonSubexpressionEliminator::optimizeBreakingItem() { - if (!m_breakingItem || *m_breakingItem != AssemblyItem(Instruction::JUMPI)) + if (!m_breakingItem) return; + ExpressionClasses& classes = m_state.expressionClasses(); SourceLocation const& location = m_breakingItem->getLocation(); - AssemblyItem::JumpType jumpType = m_breakingItem->getJumpType(); - - Id condition = m_state.stackElement(m_state.stackHeight() - 1, location); - Id zero = m_state.expressionClasses().find(u256(0)); - if (m_state.expressionClasses().knownToBeDifferent(condition, zero)) + if (*m_breakingItem == AssemblyItem(Instruction::JUMPI)) { - feedItem(AssemblyItem(Instruction::SWAP1, location), true); - feedItem(AssemblyItem(Instruction::POP, location), true); + AssemblyItem::JumpType jumpType = m_breakingItem->getJumpType(); - AssemblyItem item(Instruction::JUMP, location); - item.setJumpType(jumpType); - m_breakingItem = m_state.expressionClasses().storeItem(item); - return; + Id condition = m_state.stackElement(m_state.stackHeight() - 1, location); + if (classes.knownNonZero(condition)) + { + feedItem(AssemblyItem(Instruction::SWAP1, location), true); + feedItem(AssemblyItem(Instruction::POP, location), true); + + AssemblyItem item(Instruction::JUMP, location); + item.setJumpType(jumpType); + m_breakingItem = classes.storeItem(item); + } + else if (classes.knownZero(condition)) + { + AssemblyItem it(Instruction::POP, location); + feedItem(it, true); + feedItem(it, true); + m_breakingItem = nullptr; + } } - Id negatedCondition = m_state.expressionClasses().find(Instruction::ISZERO, {condition}); - if (m_state.expressionClasses().knownToBeDifferent(negatedCondition, zero)) + else if (*m_breakingItem == AssemblyItem(Instruction::RETURN)) { - AssemblyItem it(Instruction::POP, location); - feedItem(it, true); - feedItem(it, true); - m_breakingItem = nullptr; + Id size = m_state.stackElement(m_state.stackHeight() - 1, location); + if (classes.knownZero(size)) + { + feedItem(AssemblyItem(Instruction::POP, location), true); + feedItem(AssemblyItem(Instruction::POP, location), true); + AssemblyItem item(Instruction::STOP, location); + m_breakingItem = classes.storeItem(item); + } } } diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 950b1e756..b2b8bfa4c 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -298,7 +298,10 @@ void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters) stackDepth -= type->getSizeOnStack(); } // note that the stack is not cleaned up here - m_context << u256(dataOffset) << u256(0) << eth::Instruction::RETURN; + if (dataOffset == 0) + m_context << eth::Instruction::STOP; + else + m_context << u256(dataOffset) << u256(0) << eth::Instruction::RETURN; } void Compiler::registerStateVariables(ContractDefinition const& _contract) diff --git a/test/libsolidity/SolidityOptimizer.cpp b/test/libsolidity/SolidityOptimizer.cpp index 397ee6316..85a88c030 100644 --- a/test/libsolidity/SolidityOptimizer.cpp +++ b/test/libsolidity/SolidityOptimizer.cpp @@ -944,6 +944,14 @@ BOOST_AUTO_TEST_CASE(cse_access_previous_sequence) // 0, SLOAD, 1, ADD, SSTORE, 0 SLOAD } +BOOST_AUTO_TEST_CASE(cse_optimise_return) +{ + checkCSE( + AssemblyItems{u256(0), u256(7), Instruction::RETURN}, + AssemblyItems{Instruction::STOP} + ); +} + BOOST_AUTO_TEST_CASE(control_flow_graph_remove_unused) { // remove parts of the code that are unused From 4b2d62814f42ce77be5cac76d6e9920e114585df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 12 Jun 2015 11:15:47 +0200 Subject: [PATCH 31/40] Change stack offloading point. --- libethereum/ExtVM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libethereum/ExtVM.cpp b/libethereum/ExtVM.cpp index d9ff738ed..b32d308f2 100644 --- a/libethereum/ExtVM.cpp +++ b/libethereum/ExtVM.cpp @@ -30,7 +30,7 @@ using namespace dev::eth; namespace { static unsigned const c_depthLimit = 1024; -static size_t const c_singleExecutionStackSize = 8 * 1024; +static size_t const c_singleExecutionStackSize = 12 * 1024; static size_t const c_defaultStackSize = 512 * 1024; static unsigned const c_offloadPoint = c_defaultStackSize / c_singleExecutionStackSize; From ed65ebdede34bcfa744df1b914cd723ba7af27a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 12 Jun 2015 13:27:26 +0200 Subject: [PATCH 32/40] Remove debug logs and add comments. --- libethereum/ExtVM.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/libethereum/ExtVM.cpp b/libethereum/ExtVM.cpp index b32d308f2..305462511 100644 --- a/libethereum/ExtVM.cpp +++ b/libethereum/ExtVM.cpp @@ -29,28 +29,35 @@ using namespace dev::eth; namespace { + static unsigned const c_depthLimit = 1024; + +/// Upper bound of stack space needed by single CALL/CREATE execution. Set experimentally. static size_t const c_singleExecutionStackSize = 12 * 1024; + +/// Standard OSX thread stack limit. Should be reasonable for other platforms too. static size_t const c_defaultStackSize = 512 * 1024; + +/// On what depth execution should be offloaded to additional separated stack space. static unsigned const c_offloadPoint = c_defaultStackSize / c_singleExecutionStackSize; void goOnOffloadedStack(Executive& _e, OnOpFunc const& _onOp) { - cnote << "CALL OFFLOADING: offloading point " << c_offloadPoint; + // Set new stack size enouth to handle the rest of the calls up to the limit. boost::thread::attributes attrs; attrs.set_stack_size((c_depthLimit - c_offloadPoint) * c_singleExecutionStackSize); + // Create new thread with big stack and join immediately. + // TODO: It is possible to switch the implementation to Boost.Context or similar when the API is stable. std::exception_ptr exception; boost::thread{attrs, [&]{ - cnote << "OFFLOADING thread"; try { _e.go(_onOp); } catch (...) { - cnote << "!!!!!!!!!!! exception in offloading!!!!!!!!!!!!"; - exception = std::current_exception(); + exception = std::current_exception(); // Catch all exceptions to be rethrown in parent thread. } }}.join(); if (exception) @@ -59,6 +66,10 @@ void goOnOffloadedStack(Executive& _e, OnOpFunc const& _onOp) void go(unsigned _depth, Executive& _e, OnOpFunc const& _onOp) { + // If in the offloading point we need to switch to additional separated stack space. + // Current stack is too small to handle more CALL/CREATE executions. + // It needs to be done only once as newly allocated stack space it enough to handle + // the rest of the calls up to the depth limit (c_depthLimit). if (_depth == c_offloadPoint) goOnOffloadedStack(_e, _onOp); else From b84c28e0849cfc59f68f2ca6be90edda02f03648 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 12 Jun 2015 15:46:09 +0200 Subject: [PATCH 33/40] Allow forcing single chunk DAG upload to GPU A new argument is added. --force-single-chunk allows the user to overwrite auto chunk detection and force DAG uploading in a single chunk. This should only be used if the user is 100% certain that their card can actually enqueue a DAG for writting bigger than the MAX_MEM_ALLOC_SIZE. OpenCL says this is undefined behaviour so use at your own risk. Still, some cards seem to be able to upload the DAG in a single chunk even if OpenCL thinks they can't, thus the decision to add this option. --- ethminer/MinerAux.h | 5 +++++ libethash-cl/ethash_cl_miner.cpp | 18 ++++++++++++++---- libethash-cl/ethash_cl_miner.h | 9 ++++++++- libethcore/Ethash.cpp | 3 ++- libethcore/Ethash.h | 3 ++- 5 files changed, 31 insertions(+), 7 deletions(-) diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index f49fbd70d..6de3913e4 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -134,6 +134,8 @@ public: m_clAllowCPU = true; else if (arg == "--cl-extragpu-mem" && i + 1 < argc) m_extraGPUMemory = 1000000 * stol(argv[++i]); + else if (arg == "--force-single-chunk") + m_forceSingleChunk = true; else if (arg == "--phone-home" && i + 1 < argc) { string m = argv[++i]; @@ -271,6 +273,7 @@ public: m_openclDevice, m_clAllowCPU, m_extraGPUMemory, + m_forceSingleChunk, m_currentBlock )) { @@ -318,6 +321,7 @@ public: << " --list-devices List the detected OpenCL devices and exit." < m_currentBlock; // default value is 350MB of GPU memory for other stuff (windows system rendering, e.t.c.) unsigned m_extraGPUMemory = 350000000; diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 5f36393c6..6c2f8269a 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -137,9 +137,15 @@ unsigned ethash_cl_miner::getNumDevices(unsigned _platformId) return devices.size(); } -bool ethash_cl_miner::configureGPU(bool _allowCPU, unsigned _extraGPUMemory, boost::optional _currentBlock) +bool ethash_cl_miner::configureGPU( + bool _allowCPU, + unsigned _extraGPUMemory, + bool _forceSingleChunk, + boost::optional _currentBlock +) { s_allowCPU = _allowCPU; + s_forceSingleChunk = _forceSingleChunk; s_extraRequiredGPUMem = _extraGPUMemory; // by default let's only consider the DAG of the first epoch uint64_t dagSize = _currentBlock ? ethash_get_datasize(*_currentBlock) : 1073739904U; @@ -168,6 +174,7 @@ bool ethash_cl_miner::configureGPU(bool _allowCPU, unsigned _extraGPUMemory, boo } bool ethash_cl_miner::s_allowCPU = false; +bool ethash_cl_miner::s_forceSingleChunk = false; unsigned ethash_cl_miner::s_extraRequiredGPUMem; bool ethash_cl_miner::searchForAllDevices(function _callback) @@ -284,15 +291,18 @@ bool ethash_cl_miner::init( // configure chunk number depending on max allocateable memory cl_ulong result; device.getInfo(CL_DEVICE_MAX_MEM_ALLOC_SIZE, &result); - if (result >= _dagSize) + if (s_forceSingleChunk || result >= _dagSize) { m_dagChunksNum = 1; - ETHCL_LOG("Using 1 big chunk. Max OpenCL allocateable memory is" << result); + ETHCL_LOG( + ((result <= _dagSize && s_forceSingleChunk) ? "Forcing single chunk. Good luck!\n" : "") << + "Using 1 big chunk. Max OpenCL allocateable memory is " << result + ); } else { m_dagChunksNum = 4; - ETHCL_LOG("Using 4 chunks. Max OpenCL allocateable memory is" << result); + ETHCL_LOG("Using 4 chunks. Max OpenCL allocateable memory is " << result); } if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0) diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index b17fdeeb4..cc01b0057 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -41,7 +41,12 @@ public: static unsigned getNumDevices(unsigned _platformId = 0); static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0); static void listDevices(); - static bool configureGPU(bool _allowCPU, unsigned _extraGPUMemory, boost::optional _currentBlock); + static bool configureGPU( + bool _allowCPU, + unsigned _extraGPUMemory, + bool _forceSingleChunk, + boost::optional _currentBlock + ); bool init( uint8_t const* _dag, @@ -74,6 +79,8 @@ private: unsigned m_workgroup_size; bool m_opencl_1_1; + /// Force dag upload to GPU in a single chunk even if OpenCL thinks you can't do it. Use at your own risk. + static bool s_forceSingleChunk; /// Allow CPU to appear as an OpenCL device or not. Default is false static bool s_allowCPU; /// GPU memory required for other things, like window rendering e.t.c. diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index 8600dd51a..2c743f33b 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -386,12 +386,13 @@ bool Ethash::GPUMiner::configureGPU( unsigned _deviceId, bool _allowCPU, unsigned _extraGPUMemory, + bool _forceSingleChunk, boost::optional _currentBlock ) { s_platformId = _platformId; s_deviceId = _deviceId; - return ethash_cl_miner::configureGPU(_allowCPU, _extraGPUMemory, _currentBlock); + return ethash_cl_miner::configureGPU(_allowCPU, _extraGPUMemory, _forceSingleChunk, _currentBlock); } #endif diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index d9584f0d4..a5a7856f1 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -88,7 +88,7 @@ public: static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static std::string platformInfo(); static void listDevices() {} - static bool configureGPU(unsigned, unsigned, bool, unsigned, boost::optional) { return false; } + static bool configureGPU(unsigned, unsigned, bool, unsigned, bool, boost::optional) { return false; } static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } protected: void kickOff() override @@ -122,6 +122,7 @@ public: unsigned _deviceId, bool _allowCPU, unsigned _extraGPUMemory, + bool _forceSingleChunk, boost::optional _currentBlock ); static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } From 113acd7bba5481565dad1862c2e883251571334d Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 12 Jun 2015 18:12:21 +0200 Subject: [PATCH 34/40] made signals/handler not dependent on destruction order --- libethcore/Common.h | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/libethcore/Common.h b/libethcore/Common.h index 64eb6de29..6f23cb0e8 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -123,28 +123,43 @@ struct ImportRequirements class Signal { public: + using Callback = std::function; + class HandlerAux { friend class Signal; public: ~HandlerAux() { if (m_s) m_s->m_fire.erase(m_i); m_s = nullptr; } + void reset() { m_s = nullptr; } + void fire() { m_h(); } private: - HandlerAux(unsigned _i, Signal* _s): m_i(_i), m_s(_s) {} + HandlerAux(unsigned _i, Signal* _s, Callback const& _h): m_i(_i), m_s(_s), m_h(_h) {} unsigned m_i = 0; Signal* m_s = nullptr; + Callback m_h; }; - using Callback = std::function; + ~Signal() + { + for (auto const& h : m_fire) + h.second->reset(); + } - std::shared_ptr add(Callback const& _h) { auto n = m_fire.empty() ? 0 : (m_fire.rbegin()->first + 1); m_fire[n] = _h; return std::shared_ptr(new HandlerAux(n, this)); } + std::shared_ptr add(Callback const& _h) + { + auto n = m_fire.empty() ? 0 : (m_fire.rbegin()->first + 1); + auto h = std::shared_ptr(new HandlerAux(n, this, _h)); + m_fire[n] = h; + return h; + } - void operator()() { for (auto const& f: m_fire) f.second(); } + void operator()() { for (auto const& f: m_fire) f.second->fire(); } private: - std::map m_fire; + std::map> m_fire; }; using Handler = std::shared_ptr; From eb140df18ae82f7e79b6c53553486026c20dac06 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 13 Jun 2015 17:46:16 +0800 Subject: [PATCH 35/40] Admin methods. --- libdevcore/Common.cpp | 2 +- libethereum/Client.cpp | 75 +- libethereum/Client.h | 2 + libjsqrc/ethereumjs/dist/web3-light.js | 5586 ------------------- libjsqrc/ethereumjs/dist/web3-light.min.js | 2 - libjsqrc/ethereumjs/dist/web3.js | 27 +- libjsqrc/ethereumjs/dist/web3.min.js | 4 +- libjsqrc/ethereumjs/gulpfile.js | 2 +- libjsqrc/ethereumjs/lib/web3.js | 5 +- libjsqrc/ethereumjs/lib/web3/property.js | 1 + libweb3jsonrpc/WebThreeStubServer.h | 2 +- libweb3jsonrpc/WebThreeStubServerBase.cpp | 77 + libweb3jsonrpc/WebThreeStubServerBase.h | 26 +- libweb3jsonrpc/abstractwebthreestubserver.h | 126 + libweb3jsonrpc/spec.json | 23 +- test/libweb3jsonrpc/webthreestubclient.h | 227 + 16 files changed, 552 insertions(+), 5635 deletions(-) delete mode 100644 libjsqrc/ethereumjs/dist/web3-light.js delete mode 100644 libjsqrc/ethereumjs/dist/web3-light.min.js diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 5fe2775d2..22ea584c1 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -28,7 +28,7 @@ using namespace dev; namespace dev { -char const* Version = "0.9.25"; +char const* Version = "0.9.26"; const u256 UndefinedU256 = ~(u256)0; diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 304185a4d..657e25772 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -611,11 +611,21 @@ bool Client::submitWork(ProofOfWork::Solution const& _solution) return true; } +unsigned static const c_syncMin = 1; +unsigned static const c_syncMax = 100; +double static const c_targetDuration = 0.5; + void Client::syncBlockQueue() { ImportRoute ir; cwork << "BQ ==> CHAIN ==> STATE"; - tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, rand() % 10 + 5); + boost::timer t; + tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, m_syncAmount); + double elapsed = t.elapsed(); + if (elapsed > 0.55 && m_syncAmount > c_syncMin) + m_syncAmount = max(c_syncMin, m_syncAmount * 9 / 10); + else if (elapsed < 0.45 && m_syncAmount < c_syncMax) + m_syncAmount = min(c_syncMax, m_syncAmount * 11 / 10 + 1); if (ir.first.empty()) return; onChainChanged(ir); @@ -688,43 +698,46 @@ void Client::onChainChanged(ImportRoute const& _ir) // RESTART MINING - bool preChanged = false; - State newPreMine; - DEV_READ_GUARDED(x_preMine) - newPreMine = m_preMine; + if (!m_bq.items().first) + { + bool preChanged = false; + State newPreMine; + DEV_READ_GUARDED(x_preMine) + newPreMine = m_preMine; - // TODO: use m_postMine to avoid re-evaluating our own blocks. - preChanged = newPreMine.sync(m_bc); + // TODO: use m_postMine to avoid re-evaluating our own blocks. + preChanged = newPreMine.sync(m_bc); - if (preChanged || m_postMine.address() != m_preMine.address()) - { - if (isMining()) - cnote << "New block on chain."; + if (preChanged || m_postMine.address() != m_preMine.address()) + { + if (isMining()) + cnote << "New block on chain."; + + DEV_WRITE_GUARDED(x_preMine) + m_preMine = newPreMine; + DEV_WRITE_GUARDED(x_working) + m_working = newPreMine; + DEV_READ_GUARDED(x_postMine) + for (auto const& t: m_postMine.pending()) + { + clog(ClientNote) << "Resubmitting post-mine transaction " << t; + auto ir = m_tq.import(t, TransactionQueue::ImportCallback(), IfDropped::Retry); + if (ir != ImportResult::Success) + onTransactionQueueReady(); + } + DEV_READ_GUARDED(x_working) DEV_WRITE_GUARDED(x_postMine) + m_postMine = m_working; - DEV_WRITE_GUARDED(x_preMine) - m_preMine = newPreMine; - DEV_WRITE_GUARDED(x_working) - m_working = newPreMine; - DEV_READ_GUARDED(x_postMine) - for (auto const& t: m_postMine.pending()) - { - clog(ClientNote) << "Resubmitting post-mine transaction " << t; - auto ir = m_tq.import(t, TransactionQueue::ImportCallback(), IfDropped::Retry); - if (ir != ImportResult::Success) - onTransactionQueueReady(); - } - DEV_READ_GUARDED(x_working) DEV_WRITE_GUARDED(x_postMine) - m_postMine = m_working; + changeds.insert(PendingChangedFilter); - changeds.insert(PendingChangedFilter); + onPostStateChanged(); + } - onPostStateChanged(); + // Quick hack for now - the TQ at this point already has the prior pending transactions in it; + // we should resync with it manually until we are stricter about what constitutes "knowing". + onTransactionQueueReady(); } - // Quick hack for now - the TQ at this point already has the prior pending transactions in it; - // we should resync with it manually until we are stricter about what constitutes "knowing". - onTransactionQueueReady(); - noteChanged(changeds); } diff --git a/libethereum/Client.h b/libethereum/Client.h index 5cae50ed0..b70f01155 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -338,6 +338,8 @@ private: mutable std::chrono::system_clock::time_point m_lastTick = std::chrono::system_clock::now(); ///< When did we last tick()? + unsigned m_syncAmount = 50; ///< Number of blocks to sync in each go. + ActivityReport m_report; std::condition_variable m_signalled; diff --git a/libjsqrc/ethereumjs/dist/web3-light.js b/libjsqrc/ethereumjs/dist/web3-light.js deleted file mode 100644 index c1452e786..000000000 --- a/libjsqrc/ethereumjs/dist/web3-light.js +++ /dev/null @@ -1,5586 +0,0 @@ -require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o. -*/ -/** - * @file coder.js - * @author Marek Kotewicz - * @date 2015 - */ - -var BigNumber = require('bignumber.js'); -var utils = require('../utils/utils'); -var f = require('./formatters'); -var SolidityParam = require('./param'); - -/** - * Should be used to check if a type is an array type - * - * @method isArrayType - * @param {String} type - * @return {Bool} true is the type is an array, otherwise false - */ -var isArrayType = function (type) { - return type.slice(-2) === '[]'; -}; - -/** - * SolidityType prototype is used to encode/decode solidity params of certain type - */ -var SolidityType = function (config) { - this._name = config.name; - this._match = config.match; - this._mode = config.mode; - this._inputFormatter = config.inputFormatter; - this._outputFormatter = config.outputFormatter; -}; - -/** - * Should be used to determine if this SolidityType do match given type - * - * @method isType - * @param {String} name - * @return {Bool} true if type match this SolidityType, otherwise false - */ -SolidityType.prototype.isType = function (name) { - if (this._match === 'strict') { - return this._name === name || (name.indexOf(this._name) === 0 && name.slice(this._name.length) === '[]'); - } else if (this._match === 'prefix') { - // TODO better type detection! - return name.indexOf(this._name) === 0; - } -}; - -/** - * Should be used to transform plain param to SolidityParam object - * - * @method formatInput - * @param {Object} param - plain object, or an array of objects - * @param {Bool} arrayType - true if a param should be encoded as an array - * @return {SolidityParam} encoded param wrapped in SolidityParam object - */ -SolidityType.prototype.formatInput = function (param, arrayType) { - if (utils.isArray(param) && arrayType) { // TODO: should fail if this two are not the same - var self = this; - return param.map(function (p) { - return self._inputFormatter(p); - }).reduce(function (acc, current) { - return acc.combine(current); - }, f.formatInputInt(param.length)).withOffset(32); - } - return this._inputFormatter(param); -}; - -/** - * Should be used to transoform SolidityParam to plain param - * - * @method formatOutput - * @param {SolidityParam} byteArray - * @param {Bool} arrayType - true if a param should be decoded as an array - * @return {Object} plain decoded param - */ -SolidityType.prototype.formatOutput = function (param, arrayType) { - if (arrayType) { - // let's assume, that we solidity will never return long arrays :P - var result = []; - var length = new BigNumber(param.dynamicPart().slice(0, 64), 16); - for (var i = 0; i < length * 64; i += 64) { - result.push(this._outputFormatter(new SolidityParam(param.dynamicPart().substr(i + 64, 64)))); - } - return result; - } - return this._outputFormatter(param); -}; - -/** - * Should be used to slice single param from bytes - * - * @method sliceParam - * @param {String} bytes - * @param {Number} index of param to slice - * @param {String} type - * @returns {SolidityParam} param - */ -SolidityType.prototype.sliceParam = function (bytes, index, type) { - if (this._mode === 'bytes') { - return SolidityParam.decodeBytes(bytes, index); - } else if (isArrayType(type)) { - return SolidityParam.decodeArray(bytes, index); - } - return SolidityParam.decodeParam(bytes, index); -}; - -/** - * SolidityCoder prototype should be used to encode/decode solidity params of any type - */ -var SolidityCoder = function (types) { - this._types = types; -}; - -/** - * This method should be used to transform type to SolidityType - * - * @method _requireType - * @param {String} type - * @returns {SolidityType} - * @throws {Error} throws if no matching type is found - */ -SolidityCoder.prototype._requireType = function (type) { - var solidityType = this._types.filter(function (t) { - return t.isType(type); - })[0]; - - if (!solidityType) { - throw Error('invalid solidity type!: ' + type); - } - - return solidityType; -}; - -/** - * Should be used to transform plain param of given type to SolidityParam - * - * @method _formatInput - * @param {String} type of param - * @param {Object} plain param - * @return {SolidityParam} - */ -SolidityCoder.prototype._formatInput = function (type, param) { - return this._requireType(type).formatInput(param, isArrayType(type)); -}; - -/** - * Should be used to encode plain param - * - * @method encodeParam - * @param {String} type - * @param {Object} plain param - * @return {String} encoded plain param - */ -SolidityCoder.prototype.encodeParam = function (type, param) { - return this._formatInput(type, param).encode(); -}; - -/** - * Should be used to encode list of params - * - * @method encodeParams - * @param {Array} types - * @param {Array} params - * @return {String} encoded list of params - */ -SolidityCoder.prototype.encodeParams = function (types, params) { - var self = this; - var solidityParams = types.map(function (type, index) { - return self._formatInput(type, params[index]); - }); - - return SolidityParam.encodeList(solidityParams); -}; - -/** - * Should be used to decode bytes to plain param - * - * @method decodeParam - * @param {String} type - * @param {String} bytes - * @return {Object} plain param - */ -SolidityCoder.prototype.decodeParam = function (type, bytes) { - return this.decodeParams([type], bytes)[0]; -}; - -/** - * Should be used to decode list of params - * - * @method decodeParam - * @param {Array} types - * @param {String} bytes - * @return {Array} array of plain params - */ -SolidityCoder.prototype.decodeParams = function (types, bytes) { - var self = this; - return types.map(function (type, index) { - var solidityType = self._requireType(type); - var p = solidityType.sliceParam(bytes, index, type); - return solidityType.formatOutput(p, isArrayType(type)); - }); -}; - -var coder = new SolidityCoder([ - new SolidityType({ - name: 'address', - match: 'strict', - mode: 'value', - inputFormatter: f.formatInputInt, - outputFormatter: f.formatOutputAddress - }), - new SolidityType({ - name: 'bool', - match: 'strict', - mode: 'value', - inputFormatter: f.formatInputBool, - outputFormatter: f.formatOutputBool - }), - new SolidityType({ - name: 'int', - match: 'prefix', - mode: 'value', - inputFormatter: f.formatInputInt, - outputFormatter: f.formatOutputInt, - }), - new SolidityType({ - name: 'uint', - match: 'prefix', - mode: 'value', - inputFormatter: f.formatInputInt, - outputFormatter: f.formatOutputUInt - }), - new SolidityType({ - name: 'bytes', - match: 'strict', - mode: 'bytes', - inputFormatter: f.formatInputDynamicBytes, - outputFormatter: f.formatOutputDynamicBytes - }), - new SolidityType({ - name: 'bytes', - match: 'prefix', - mode: 'value', - inputFormatter: f.formatInputBytes, - outputFormatter: f.formatOutputBytes - }), - new SolidityType({ - name: 'real', - match: 'prefix', - mode: 'value', - inputFormatter: f.formatInputReal, - outputFormatter: f.formatOutputReal - }), - new SolidityType({ - name: 'ureal', - match: 'prefix', - mode: 'value', - inputFormatter: f.formatInputReal, - outputFormatter: f.formatOutputUReal - }) -]); - -module.exports = coder; - - -},{"../utils/utils":7,"./formatters":2,"./param":3,"bignumber.js":"bignumber.js"}],2:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** - * @file formatters.js - * @author Marek Kotewicz - * @date 2015 - */ - -var BigNumber = require('bignumber.js'); -var utils = require('../utils/utils'); -var c = require('../utils/config'); -var SolidityParam = require('./param'); - - -/** - * Formats input value to byte representation of int - * If value is negative, return it's two's complement - * If the value is floating point, round it down - * - * @method formatInputInt - * @param {String|Number|BigNumber} value that needs to be formatted - * @returns {SolidityParam} - */ -var formatInputInt = function (value) { - var padding = c.ETH_PADDING * 2; - BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE); - var result = utils.padLeft(utils.toTwosComplement(value).round().toString(16), padding); - return new SolidityParam(result); -}; - -/** - * Formats input value to byte representation of string - * - * @method formatInputBytes - * @param {String} - * @returns {SolidityParam} - */ -var formatInputBytes = function (value) { - var result = utils.fromAscii(value, c.ETH_PADDING).substr(2); - return new SolidityParam(result); -}; - -/** - * Formats input value to byte representation of string - * - * @method formatInputDynamicBytes - * @param {String} - * @returns {SolidityParam} - */ -var formatInputDynamicBytes = function (value) { - var result = utils.fromAscii(value, c.ETH_PADDING).substr(2); - return new SolidityParam(formatInputInt(value.length).value + result, 32); -}; - -/** - * Formats input value to byte representation of bool - * - * @method formatInputBool - * @param {Boolean} - * @returns {SolidityParam} - */ -var formatInputBool = function (value) { - var result = '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0'); - return new SolidityParam(result); -}; - -/** - * Formats input value to byte representation of real - * Values are multiplied by 2^m and encoded as integers - * - * @method formatInputReal - * @param {String|Number|BigNumber} - * @returns {SolidityParam} - */ -var formatInputReal = function (value) { - return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128))); -}; - -/** - * Check if input value is negative - * - * @method signedIsNegative - * @param {String} value is hex format - * @returns {Boolean} true if it is negative, otherwise false - */ -var signedIsNegative = function (value) { - return (new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1'; -}; - -/** - * Formats right-aligned output bytes to int - * - * @method formatOutputInt - * @param {SolidityParam} param - * @returns {BigNumber} right-aligned output bytes formatted to big number - */ -var formatOutputInt = function (param) { - var value = param.staticPart() || "0"; - - // check if it's negative number - // it it is, return two's complement - if (signedIsNegative(value)) { - return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1); - } - return new BigNumber(value, 16); -}; - -/** - * Formats right-aligned output bytes to uint - * - * @method formatOutputUInt - * @param {SolidityParam} - * @returns {BigNumeber} right-aligned output bytes formatted to uint - */ -var formatOutputUInt = function (param) { - var value = param.staticPart() || "0"; - return new BigNumber(value, 16); -}; - -/** - * Formats right-aligned output bytes to real - * - * @method formatOutputReal - * @param {SolidityParam} - * @returns {BigNumber} input bytes formatted to real - */ -var formatOutputReal = function (param) { - return formatOutputInt(param).dividedBy(new BigNumber(2).pow(128)); -}; - -/** - * Formats right-aligned output bytes to ureal - * - * @method formatOutputUReal - * @param {SolidityParam} - * @returns {BigNumber} input bytes formatted to ureal - */ -var formatOutputUReal = function (param) { - return formatOutputUInt(param).dividedBy(new BigNumber(2).pow(128)); -}; - -/** - * Should be used to format output bool - * - * @method formatOutputBool - * @param {SolidityParam} - * @returns {Boolean} right-aligned input bytes formatted to bool - */ -var formatOutputBool = function (param) { - return param.staticPart() === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false; -}; - -/** - * Should be used to format output string - * - * @method formatOutputBytes - * @param {SolidityParam} left-aligned hex representation of string - * @returns {String} ascii string - */ -var formatOutputBytes = function (param) { - // length might also be important! - return utils.toAscii(param.staticPart()); -}; - -/** - * Should be used to format output string - * - * @method formatOutputDynamicBytes - * @param {SolidityParam} left-aligned hex representation of string - * @returns {String} ascii string - */ -var formatOutputDynamicBytes = function (param) { - // length might also be important! - return utils.toAscii(param.dynamicPart().slice(64)); -}; - -/** - * Should be used to format output address - * - * @method formatOutputAddress - * @param {SolidityParam} right-aligned input bytes - * @returns {String} address - */ -var formatOutputAddress = function (param) { - var value = param.staticPart(); - return "0x" + value.slice(value.length - 40, value.length); -}; - -module.exports = { - formatInputInt: formatInputInt, - formatInputBytes: formatInputBytes, - formatInputDynamicBytes: formatInputDynamicBytes, - formatInputBool: formatInputBool, - formatInputReal: formatInputReal, - formatOutputInt: formatOutputInt, - formatOutputUInt: formatOutputUInt, - formatOutputReal: formatOutputReal, - formatOutputUReal: formatOutputUReal, - formatOutputBool: formatOutputBool, - formatOutputBytes: formatOutputBytes, - formatOutputDynamicBytes: formatOutputDynamicBytes, - formatOutputAddress: formatOutputAddress -}; - - -},{"../utils/config":5,"../utils/utils":7,"./param":3,"bignumber.js":"bignumber.js"}],3:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** - * @file param.js - * @author Marek Kotewicz - * @date 2015 - */ - -var utils = require('../utils/utils'); - -/** - * SolidityParam object prototype. - * Should be used when encoding, decoding solidity bytes - */ -var SolidityParam = function (value, offset) { - this.value = value || ''; - this.offset = offset; // offset in bytes -}; - -/** - * This method should be used to get length of params's dynamic part - * - * @method dynamicPartLength - * @returns {Number} length of dynamic part (in bytes) - */ -SolidityParam.prototype.dynamicPartLength = function () { - return this.dynamicPart().length / 2; -}; - -/** - * This method should be used to create copy of solidity param with different offset - * - * @method withOffset - * @param {Number} offset length in bytes - * @returns {SolidityParam} new solidity param with applied offset - */ -SolidityParam.prototype.withOffset = function (offset) { - return new SolidityParam(this.value, offset); -}; - -/** - * This method should be used to combine solidity params together - * eg. when appending an array - * - * @method combine - * @param {SolidityParam} param with which we should combine - * @param {SolidityParam} result of combination - */ -SolidityParam.prototype.combine = function (param) { - return new SolidityParam(this.value + param.value); -}; - -/** - * This method should be called to check if param has dynamic size. - * If it has, it returns true, otherwise false - * - * @method isDynamic - * @returns {Boolean} - */ -SolidityParam.prototype.isDynamic = function () { - return this.value.length > 64 || this.offset !== undefined; -}; - -/** - * This method should be called to transform offset to bytes - * - * @method offsetAsBytes - * @returns {String} bytes representation of offset - */ -SolidityParam.prototype.offsetAsBytes = function () { - return !this.isDynamic() ? '' : utils.padLeft(utils.toTwosComplement(this.offset).toString(16), 64); -}; - -/** - * This method should be called to get static part of param - * - * @method staticPart - * @returns {String} offset if it is a dynamic param, otherwise value - */ -SolidityParam.prototype.staticPart = function () { - if (!this.isDynamic()) { - return this.value; - } - return this.offsetAsBytes(); -}; - -/** - * This method should be called to get dynamic part of param - * - * @method dynamicPart - * @returns {String} returns a value if it is a dynamic param, otherwise empty string - */ -SolidityParam.prototype.dynamicPart = function () { - return this.isDynamic() ? this.value : ''; -}; - -/** - * This method should be called to encode param - * - * @method encode - * @returns {String} - */ -SolidityParam.prototype.encode = function () { - return this.staticPart() + this.dynamicPart(); -}; - -/** - * This method should be called to encode array of params - * - * @method encodeList - * @param {Array[SolidityParam]} params - * @returns {String} - */ -SolidityParam.encodeList = function (params) { - - // updating offsets - var totalOffset = params.length * 32; - var offsetParams = params.map(function (param) { - if (!param.isDynamic()) { - return param; - } - var offset = totalOffset; - totalOffset += param.dynamicPartLength(); - return param.withOffset(offset); - }); - - // encode everything! - return offsetParams.reduce(function (result, param) { - return result + param.dynamicPart(); - }, offsetParams.reduce(function (result, param) { - return result + param.staticPart(); - }, '')); -}; - -/** - * This method should be used to decode plain (static) solidity param at given index - * - * @method decodeParam - * @param {String} bytes - * @param {Number} index - * @returns {SolidityParam} - */ -SolidityParam.decodeParam = function (bytes, index) { - index = index || 0; - return new SolidityParam(bytes.substr(index * 64, 64)); -}; - -/** - * This method should be called to get offset value from bytes at given index - * - * @method getOffset - * @param {String} bytes - * @param {Number} index - * @returns {Number} offset as number - */ -var getOffset = function (bytes, index) { - // we can do this cause offset is rather small - return parseInt('0x' + bytes.substr(index * 64, 64)); -}; - -/** - * This method should be called to decode solidity bytes param at given index - * - * @method decodeBytes - * @param {String} bytes - * @param {Number} index - * @returns {SolidityParam} - */ -SolidityParam.decodeBytes = function (bytes, index) { - index = index || 0; - //TODO add support for strings longer than 32 bytes - //var length = parseInt('0x' + bytes.substr(offset * 64, 64)); - - var offset = getOffset(bytes, index); - - // 2 * , cause we also parse length - return new SolidityParam(bytes.substr(offset * 2, 2 * 64), 0); -}; - -/** - * This method should be used to decode solidity array at given index - * - * @method decodeArray - * @param {String} bytes - * @param {Number} index - * @returns {SolidityParam} - */ -SolidityParam.decodeArray = function (bytes, index) { - index = index || 0; - var offset = getOffset(bytes, index); - var length = parseInt('0x' + bytes.substr(offset * 2, 64)); - return new SolidityParam(bytes.substr(offset * 2, (length + 1) * 64), 0); -}; - -module.exports = SolidityParam; - - -},{"../utils/utils":7}],4:[function(require,module,exports){ -'use strict'; - -// go env doesn't have and need XMLHttpRequest -if (typeof XMLHttpRequest === 'undefined') { - exports.XMLHttpRequest = {}; -} else { - exports.XMLHttpRequest = XMLHttpRequest; // jshint ignore:line -} - - -},{}],5:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file config.js - * @authors: - * Marek Kotewicz - * @date 2015 - */ - -/** - * Utils - * - * @module utils - */ - -/** - * Utility functions - * - * @class [utils] config - * @constructor - */ - -/// required to define ETH_BIGNUMBER_ROUNDING_MODE -var BigNumber = require('bignumber.js'); - -var ETH_UNITS = [ - 'wei', - 'kwei', - 'Mwei', - 'Gwei', - 'szabo', - 'finney', - 'femtoether', - 'picoether', - 'nanoether', - 'microether', - 'milliether', - 'nano', - 'micro', - 'milli', - 'ether', - 'grand', - 'Mether', - 'Gether', - 'Tether', - 'Pether', - 'Eether', - 'Zether', - 'Yether', - 'Nether', - 'Dether', - 'Vether', - 'Uether' -]; - -module.exports = { - ETH_PADDING: 32, - ETH_SIGNATURE_LENGTH: 4, - ETH_UNITS: ETH_UNITS, - ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }, - ETH_POLLING_TIMEOUT: 1000, - defaultBlock: 'latest', - defaultAccount: undefined -}; - - -},{"bignumber.js":"bignumber.js"}],6:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** - * @file sha3.js - * @author Marek Kotewicz - * @date 2015 - */ - -var utils = require('./utils'); -var sha3 = require('crypto-js/sha3'); - -module.exports = function (str, isNew) { - if (str.substr(0, 2) === '0x' && !isNew) { - console.warn('requirement of using web3.fromAscii before sha3 is deprecated'); - console.warn('new usage: \'web3.sha3("hello")\''); - console.warn('see https://github.com/ethereum/web3.js/pull/205'); - console.warn('if you need to hash hex value, you can do \'sha3("0xfff", true)\''); - str = utils.toAscii(str); - } - - return sha3(str, { - outputLength: 256 - }).toString(); -}; - - -},{"./utils":7,"crypto-js/sha3":33}],7:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** - * @file utils.js - * @author Marek Kotewicz - * @date 2015 - */ - -/** - * Utils - * - * @module utils - */ - -/** - * Utility functions - * - * @class [utils] utils - * @constructor - */ - -var BigNumber = require('bignumber.js'); - -var unitMap = { - 'wei': '1', - 'kwei': '1000', - 'ada': '1000', - 'femtoether': '1000', - 'mwei': '1000000', - 'babbage': '1000000', - 'picoether': '1000000', - 'gwei': '1000000000', - 'shannon': '1000000000', - 'nanoether': '1000000000', - 'nano': '1000000000', - 'szabo': '1000000000000', - 'microether': '1000000000000', - 'micro': '1000000000000', - 'finney': '1000000000000000', - 'milliether': '1000000000000000', - 'milli': '1000000000000000', - 'ether': '1000000000000000000', - 'kether': '1000000000000000000000', - 'grand': '1000000000000000000000', - 'einstein': '1000000000000000000000', - 'mether': '1000000000000000000000000', - 'gether': '1000000000000000000000000000', - 'tether': '1000000000000000000000000000000' -}; - -/** - * Should be called to pad string to expected length - * - * @method padLeft - * @param {String} string to be padded - * @param {Number} characters that result string should have - * @param {String} sign, by default 0 - * @returns {String} right aligned string - */ -var padLeft = function (string, chars, sign) { - return new Array(chars - string.length + 1).join(sign ? sign : "0") + string; -}; - -/** - * Should be called to get sting from it's hex representation - * - * @method toAscii - * @param {String} string in hex - * @returns {String} ascii string representation of hex value - */ -var toAscii = function(hex) { -// Find termination - var str = ""; - var i = 0, l = hex.length; - if (hex.substring(0, 2) === '0x') { - i = 2; - } - for (; i < l; i+=2) { - var code = parseInt(hex.substr(i, 2), 16); - if (code === 0) { - break; - } - - str += String.fromCharCode(code); - } - - return str; -}; - -/** - * Shold be called to get hex representation (prefixed by 0x) of ascii string - * - * @method toHexNative - * @param {String} string - * @returns {String} hex representation of input string - */ -var toHexNative = function(str) { - var hex = ""; - for(var i = 0; i < str.length; i++) { - var n = str.charCodeAt(i).toString(16); - hex += n.length < 2 ? '0' + n : n; - } - - return hex; -}; - -/** - * Shold be called to get hex representation (prefixed by 0x) of ascii string - * - * @method fromAscii - * @param {String} string - * @param {Number} optional padding - * @returns {String} hex representation of input string - */ -var fromAscii = function(str, pad) { - pad = pad === undefined ? 0 : pad; - var hex = toHexNative(str); - while (hex.length < pad*2) - hex += "00"; - return "0x" + hex; -}; - -/** - * Should be used to create full function/event name from json abi - * - * @method transformToFullName - * @param {Object} json-abi - * @return {String} full fnction/event name - */ -var transformToFullName = function (json) { - if (json.name.indexOf('(') !== -1) { - return json.name; - } - - var typeName = json.inputs.map(function(i){return i.type; }).join(); - return json.name + '(' + typeName + ')'; -}; - -/** - * Should be called to get display name of contract function - * - * @method extractDisplayName - * @param {String} name of function/event - * @returns {String} display name for function/event eg. multiply(uint256) -> multiply - */ -var extractDisplayName = function (name) { - var length = name.indexOf('('); - return length !== -1 ? name.substr(0, length) : name; -}; - -/// @returns overloaded part of function/event name -var extractTypeName = function (name) { - /// TODO: make it invulnerable - var length = name.indexOf('('); - return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : ""; -}; - -/** - * Converts value to it's decimal representation in string - * - * @method toDecimal - * @param {String|Number|BigNumber} - * @return {String} - */ -var toDecimal = function (value) { - return toBigNumber(value).toNumber(); -}; - -/** - * Converts value to it's hex representation - * - * @method fromDecimal - * @param {String|Number|BigNumber} - * @return {String} - */ -var fromDecimal = function (value) { - var number = toBigNumber(value); - var result = number.toString(16); - - return number.lessThan(0) ? '-0x' + result.substr(1) : '0x' + result; -}; - -/** - * Auto converts any given value into it's hex representation. - * - * And even stringifys objects before. - * - * @method toHex - * @param {String|Number|BigNumber|Object} - * @return {String} - */ -var toHex = function (val) { - /*jshint maxcomplexity:7 */ - - if (isBoolean(val)) - return fromDecimal(+val); - - if (isBigNumber(val)) - return fromDecimal(val); - - if (isObject(val)) - return fromAscii(JSON.stringify(val)); - - // if its a negative number, pass it through fromDecimal - if (isString(val)) { - if (val.indexOf('-0x') === 0) - return fromDecimal(val); - else if (!isFinite(val)) - return fromAscii(val); - } - - return fromDecimal(val); -}; - -/** - * Returns value of unit in Wei - * - * @method getValueOfUnit - * @param {String} unit the unit to convert to, default ether - * @returns {BigNumber} value of the unit (in Wei) - * @throws error if the unit is not correct:w - */ -var getValueOfUnit = function (unit) { - unit = unit ? unit.toLowerCase() : 'ether'; - var unitValue = unitMap[unit]; - if (unitValue === undefined) { - throw new Error('This unit doesn\'t exists, please use the one of the following units' + JSON.stringify(unitMap, null, 2)); - } - return new BigNumber(unitValue, 10); -}; - -/** - * Takes a number of wei and converts it to any other ether unit. - * - * Possible units are: - * SI Short SI Full Effigy Other - * - kwei femtoether ada - * - mwei picoether babbage - * - gwei nanoether shannon nano - * - -- microether szabo micro - * - -- milliether finney milli - * - ether -- -- - * - kether einstein grand - * - mether - * - gether - * - tether - * - * @method fromWei - * @param {Number|String} number can be a number, number string or a HEX of a decimal - * @param {String} unit the unit to convert to, default ether - * @return {String|Object} When given a BigNumber object it returns one as well, otherwise a number -*/ -var fromWei = function(number, unit) { - var returnValue = toBigNumber(number).dividedBy(getValueOfUnit(unit)); - - return isBigNumber(number) ? returnValue : returnValue.toString(10); -}; - -/** - * Takes a number of a unit and converts it to wei. - * - * Possible units are: - * SI Short SI Full Effigy Other - * - kwei femtoether ada - * - mwei picoether babbage - * - gwei nanoether shannon nano - * - -- microether szabo micro - * - -- milliether finney milli - * - ether -- -- - * - kether einstein grand - * - mether - * - gether - * - tether - * - * @method toWei - * @param {Number|String|BigNumber} number can be a number, number string or a HEX of a decimal - * @param {String} unit the unit to convert from, default ether - * @return {String|Object} When given a BigNumber object it returns one as well, otherwise a number -*/ -var toWei = function(number, unit) { - var returnValue = toBigNumber(number).times(getValueOfUnit(unit)); - - return isBigNumber(number) ? returnValue : returnValue.toString(10); -}; - -/** - * Takes an input and transforms it into an bignumber - * - * @method toBigNumber - * @param {Number|String|BigNumber} a number, string, HEX string or BigNumber - * @return {BigNumber} BigNumber -*/ -var toBigNumber = function(number) { - /*jshint maxcomplexity:5 */ - number = number || 0; - if (isBigNumber(number)) - return number; - - if (isString(number) && (number.indexOf('0x') === 0 || number.indexOf('-0x') === 0)) { - return new BigNumber(number.replace('0x',''), 16); - } - - return new BigNumber(number.toString(10), 10); -}; - -/** - * Takes and input transforms it into bignumber and if it is negative value, into two's complement - * - * @method toTwosComplement - * @param {Number|String|BigNumber} - * @return {BigNumber} - */ -var toTwosComplement = function (number) { - var bigNumber = toBigNumber(number); - if (bigNumber.lessThan(0)) { - return new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).plus(bigNumber).plus(1); - } - return bigNumber; -}; - -/** - * Checks if the given string is strictly an address - * - * @method isStrictAddress - * @param {String} address the given HEX adress - * @return {Boolean} -*/ -var isStrictAddress = function (address) { - return /^0x[0-9a-f]{40}$/.test(address); -}; - -/** - * Checks if the given string is an address - * - * @method isAddress - * @param {String} address the given HEX adress - * @return {Boolean} -*/ -var isAddress = function (address) { - return /^(0x)?[0-9a-f]{40}$/.test(address); -}; - -/** - * Transforms given string to valid 20 bytes-length addres with 0x prefix - * - * @method toAddress - * @param {String} address - * @return {String} formatted address - */ -var toAddress = function (address) { - if (isStrictAddress(address)) { - return address; - } - - if (/^[0-9a-f]{40}$/.test(address)) { - return '0x' + address; - } - - return '0x' + padLeft(toHex(address).substr(2), 40); -}; - - -/** - * Returns true if object is BigNumber, otherwise false - * - * @method isBigNumber - * @param {Object} - * @return {Boolean} - */ -var isBigNumber = function (object) { - return object instanceof BigNumber || - (object && object.constructor && object.constructor.name === 'BigNumber'); -}; - -/** - * Returns true if object is string, otherwise false - * - * @method isString - * @param {Object} - * @return {Boolean} - */ -var isString = function (object) { - return typeof object === 'string' || - (object && object.constructor && object.constructor.name === 'String'); -}; - -/** - * Returns true if object is function, otherwise false - * - * @method isFunction - * @param {Object} - * @return {Boolean} - */ -var isFunction = function (object) { - return typeof object === 'function'; -}; - -/** - * Returns true if object is Objet, otherwise false - * - * @method isObject - * @param {Object} - * @return {Boolean} - */ -var isObject = function (object) { - return typeof object === 'object'; -}; - -/** - * Returns true if object is boolean, otherwise false - * - * @method isBoolean - * @param {Object} - * @return {Boolean} - */ -var isBoolean = function (object) { - return typeof object === 'boolean'; -}; - -/** - * Returns true if object is array, otherwise false - * - * @method isArray - * @param {Object} - * @return {Boolean} - */ -var isArray = function (object) { - return object instanceof Array; -}; - -/** - * Returns true if given string is valid json object - * - * @method isJson - * @param {String} - * @return {Boolean} - */ -var isJson = function (str) { - try { - return !!JSON.parse(str); - } catch (e) { - return false; - } -}; - -/** - * This method should be called to check if string is valid ethereum IBAN number - * Supports direct and indirect IBANs - * - * @method isIBAN - * @param {String} - * @return {Boolean} - */ -var isIBAN = function (iban) { - return /^XE[0-9]{2}(ETH[0-9A-Z]{13}|[0-9A-Z]{30})$/.test(iban); -}; - -module.exports = { - padLeft: padLeft, - toHex: toHex, - toDecimal: toDecimal, - fromDecimal: fromDecimal, - toAscii: toAscii, - fromAscii: fromAscii, - transformToFullName: transformToFullName, - extractDisplayName: extractDisplayName, - extractTypeName: extractTypeName, - toWei: toWei, - fromWei: fromWei, - toBigNumber: toBigNumber, - toTwosComplement: toTwosComplement, - toAddress: toAddress, - isBigNumber: isBigNumber, - isStrictAddress: isStrictAddress, - isAddress: isAddress, - isFunction: isFunction, - isString: isString, - isObject: isObject, - isBoolean: isBoolean, - isArray: isArray, - isJson: isJson, - isIBAN: isIBAN -}; - - -},{"bignumber.js":"bignumber.js"}],8:[function(require,module,exports){ -module.exports={ - "version": "0.5.0" -} - -},{}],9:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file web3.js - * @authors: - * Jeffrey Wilcke - * Marek Kotewicz - * Marian Oancea - * Fabian Vogelsteller - * Gav Wood - * @date 2014 - */ - -var version = require('./version.json'); -var net = require('./web3/net'); -var eth = require('./web3/eth'); -var db = require('./web3/db'); -var shh = require('./web3/shh'); -var watches = require('./web3/watches'); -var Filter = require('./web3/filter'); -var utils = require('./utils/utils'); -var formatters = require('./web3/formatters'); -var RequestManager = require('./web3/requestmanager'); -var c = require('./utils/config'); -var Property = require('./web3/property'); -var Batch = require('./web3/batch'); -var sha3 = require('./utils/sha3'); - -var web3Properties = [ - new Property({ - name: 'version.client', - getter: 'web3_clientVersion' - }), - new Property({ - name: 'version.network', - getter: 'net_version', - inputFormatter: utils.toDecimal - }), - new Property({ - name: 'version.ethereum', - getter: 'eth_protocolVersion', - inputFormatter: utils.toDecimal - }), - new Property({ - name: 'version.whisper', - getter: 'shh_version', - inputFormatter: utils.toDecimal - }) -]; - -/// creates methods in a given object based on method description on input -/// setups api calls for these methods -var setupMethods = function (obj, methods) { - methods.forEach(function (method) { - method.attachToObject(obj); - }); -}; - -/// creates properties in a given object based on properties description on input -/// setups api calls for these properties -var setupProperties = function (obj, properties) { - properties.forEach(function (property) { - property.attachToObject(obj); - }); -}; - -/// setups web3 object, and it's in-browser executed methods -var web3 = {}; -web3.providers = {}; -web3.version = {}; -web3.version.api = version.version; -web3.eth = {}; - -/*jshint maxparams:4 */ -web3.eth.filter = function (fil, eventParams, options, formatter) { - - // if its event, treat it differently - // TODO: simplify and remove - if (fil._isEvent) { - return fil(eventParams, options); - } - - // what outputLogFormatter? that's wrong - //return new Filter(fil, watches.eth(), formatters.outputLogFormatter); - return new Filter(fil, watches.eth(), formatter || formatters.outputLogFormatter); -}; -/*jshint maxparams:3 */ - -web3.shh = {}; -web3.shh.filter = function (fil) { - return new Filter(fil, watches.shh(), formatters.outputPostFormatter); -}; -web3.net = {}; -web3.db = {}; -web3.setProvider = function (provider) { - RequestManager.getInstance().setProvider(provider); -}; -web3.reset = function () { - RequestManager.getInstance().reset(); - c.defaultBlock = 'latest'; - c.defaultAccount = undefined; -}; -web3.toHex = utils.toHex; -web3.toAscii = utils.toAscii; -web3.fromAscii = utils.fromAscii; -web3.toDecimal = utils.toDecimal; -web3.fromDecimal = utils.fromDecimal; -web3.toBigNumber = utils.toBigNumber; -web3.toWei = utils.toWei; -web3.fromWei = utils.fromWei; -web3.isAddress = utils.isAddress; -web3.isIBAN = utils.isIBAN; -web3.sha3 = sha3; -web3.createBatch = function () { - return new Batch(); -}; - -// ADD defaultblock -Object.defineProperty(web3.eth, 'defaultBlock', { - get: function () { - return c.defaultBlock; - }, - set: function (val) { - c.defaultBlock = val; - return val; - } -}); - -Object.defineProperty(web3.eth, 'defaultAccount', { - get: function () { - return c.defaultAccount; - }, - set: function (val) { - c.defaultAccount = val; - return val; - } -}); - -/// setups all api methods -setupProperties(web3, web3Properties); -setupMethods(web3.net, net.methods); -setupProperties(web3.net, net.properties); -setupMethods(web3.eth, eth.methods); -setupProperties(web3.eth, eth.properties); -setupMethods(web3.db, db.methods); -setupMethods(web3.shh, shh.methods); - -module.exports = web3; - - -},{"./utils/config":5,"./utils/sha3":6,"./utils/utils":7,"./version.json":8,"./web3/batch":10,"./web3/db":12,"./web3/eth":14,"./web3/filter":16,"./web3/formatters":17,"./web3/net":24,"./web3/property":25,"./web3/requestmanager":27,"./web3/shh":28,"./web3/watches":30}],10:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** - * @file batch.js - * @author Marek Kotewicz - * @date 2015 - */ - -var RequestManager = require('./requestmanager'); - -var Batch = function () { - this.requests = []; -}; - -/** - * Should be called to add create new request to batch request - * - * @method add - * @param {Object} jsonrpc requet object - */ -Batch.prototype.add = function (request) { - this.requests.push(request); -}; - -/** - * Should be called to execute batch request - * - * @method execute - */ -Batch.prototype.execute = function () { - var requests = this.requests; - RequestManager.getInstance().sendBatch(requests, function (err, results) { - results = results || []; - requests.map(function (request, index) { - return results[index] || {}; - }).map(function (result, index) { - return requests[index].format ? requests[index].format(result.result) : result.result; - }).forEach(function (result, index) { - if (requests[index].callback) { - requests[index].callback(err, result); - } - }); - }); -}; - -module.exports = Batch; - - -},{"./requestmanager":27}],11:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** - * @file contract.js - * @author Marek Kotewicz - * @date 2014 - */ - -var web3 = require('../web3'); -var utils = require('../utils/utils'); -var coder = require('../solidity/coder'); -var SolidityEvent = require('./event'); -var SolidityFunction = require('./function'); - -/** - * Should be called to encode constructor params - * - * @method encodeConstructorParams - * @param {Array} abi - * @param {Array} constructor params - */ -var encodeConstructorParams = function (abi, params) { - return abi.filter(function (json) { - return json.type === 'constructor' && json.inputs.length === params.length; - }).map(function (json) { - return json.inputs.map(function (input) { - return input.type; - }); - }).map(function (types) { - return coder.encodeParams(types, params); - })[0] || ''; -}; - -/** - * Should be called to add functions to contract object - * - * @method addFunctionsToContract - * @param {Contract} contract - * @param {Array} abi - */ -var addFunctionsToContract = function (contract, abi) { - abi.filter(function (json) { - return json.type === 'function'; - }).map(function (json) { - return new SolidityFunction(json, contract.address); - }).forEach(function (f) { - f.attachToContract(contract); - }); -}; - -/** - * Should be called to add events to contract object - * - * @method addEventsToContract - * @param {Contract} contract - * @param {Array} abi - */ -var addEventsToContract = function (contract, abi) { - abi.filter(function (json) { - return json.type === 'event'; - }).map(function (json) { - return new SolidityEvent(json, contract.address); - }).forEach(function (e) { - e.attachToContract(contract); - }); -}; - -/** - * Should be called to create new ContractFactory - * - * @method contract - * @param {Array} abi - * @returns {ContractFactory} new contract factory - */ -var contract = function (abi) { - return new ContractFactory(abi); -}; - -/** - * Should be called to create new ContractFactory instance - * - * @method ContractFactory - * @param {Array} abi - */ -var ContractFactory = function (abi) { - this.abi = abi; -}; - -/** - * Should be called to create new contract on a blockchain - * - * @method new - * @param {Any} contract constructor param1 (optional) - * @param {Any} contract constructor param2 (optional) - * @param {Object} contract transaction object (required) - * @param {Function} callback - * @returns {Contract} returns contract if no callback was passed, - * otherwise calls callback function (err, contract) - */ -ContractFactory.prototype.new = function () { - // parse arguments - var options = {}; // required! - var callback; - - var args = Array.prototype.slice.call(arguments); - if (utils.isFunction(args[args.length - 1])) { - callback = args.pop(); - } - - var last = args[args.length - 1]; - if (utils.isObject(last) && !utils.isArray(last)) { - options = args.pop(); - } - - // throw an error if there are no options - - var bytes = encodeConstructorParams(this.abi, args); - options.data += bytes; - - if (!callback) { - var address = web3.eth.sendTransaction(options); - return this.at(address); - } - - var self = this; - web3.eth.sendTransaction(options, function (err, address) { - if (err) { - callback(err); - } - self.at(address, callback); - }); -}; - -/** - * Should be called to get access to existing contract on a blockchain - * - * @method at - * @param {Address} contract address (required) - * @param {Function} callback {optional) - * @returns {Contract} returns contract if no callback was passed, - * otherwise calls callback function (err, contract) - */ -ContractFactory.prototype.at = function (address, callback) { - // TODO: address is required - - if (callback) { - callback(null, new Contract(this.abi, address)); - } - return new Contract(this.abi, address); -}; - -/** - * Should be called to create new contract instance - * - * @method Contract - * @param {Array} abi - * @param {Address} contract address - */ -var Contract = function (abi, address) { - this.address = address; - addFunctionsToContract(this, abi); - addEventsToContract(this, abi); -}; - -module.exports = contract; - - -},{"../solidity/coder":1,"../utils/utils":7,"../web3":9,"./event":15,"./function":18}],12:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file db.js - * @authors: - * Marek Kotewicz - * @date 2015 - */ - -var Method = require('./method'); - -var putString = new Method({ - name: 'putString', - call: 'db_putString', - params: 3 -}); - - -var getString = new Method({ - name: 'getString', - call: 'db_getString', - params: 2 -}); - -var putHex = new Method({ - name: 'putHex', - call: 'db_putHex', - params: 3 -}); - -var getHex = new Method({ - name: 'getHex', - call: 'db_getHex', - params: 2 -}); - -var methods = [ - putString, getString, putHex, getHex -]; - -module.exports = { - methods: methods -}; - -},{"./method":22}],13:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** - * @file errors.js - * @author Marek Kotewicz - * @date 2015 - */ - -module.exports = { - InvalidNumberOfParams: function () { - return new Error('Invalid number of input parameters'); - }, - InvalidConnection: function (host){ - return new Error('CONNECTION ERROR: Couldn\'t connect to node '+ host +', is it running?'); - }, - InvalidProvider: function () { - return new Error('Providor not set or invalid'); - }, - InvalidResponse: function (result){ - var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response'; - return new Error(message); - } -}; - - -},{}],14:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** - * @file eth.js - * @author Marek Kotewicz - * @author Fabian Vogelsteller - * @date 2015 - */ - -/** - * Web3 - * - * @module web3 - */ - -/** - * Eth methods and properties - * - * An example method object can look as follows: - * - * { - * name: 'getBlock', - * call: blockCall, - * params: 2, - * outputFormatter: formatters.outputBlockFormatter, - * inputFormatter: [ // can be a formatter funciton or an array of functions. Where each item in the array will be used for one parameter - * utils.toHex, // formats paramter 1 - * function(param){ return !!param; } // formats paramter 2 - * ] - * }, - * - * @class [web3] eth - * @constructor - */ - -"use strict"; - -var formatters = require('./formatters'); -var utils = require('../utils/utils'); -var Method = require('./method'); -var Property = require('./property'); - -var blockCall = function (args) { - return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? "eth_getBlockByHash" : "eth_getBlockByNumber"; -}; - -var transactionFromBlockCall = function (args) { - return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getTransactionByBlockHashAndIndex' : 'eth_getTransactionByBlockNumberAndIndex'; -}; - -var uncleCall = function (args) { - return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleByBlockHashAndIndex' : 'eth_getUncleByBlockNumberAndIndex'; -}; - -var getBlockTransactionCountCall = function (args) { - return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getBlockTransactionCountByHash' : 'eth_getBlockTransactionCountByNumber'; -}; - -var uncleCountCall = function (args) { - return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleCountByBlockHash' : 'eth_getUncleCountByBlockNumber'; -}; - -/// @returns an array of objects describing web3.eth api methods - -var getBalance = new Method({ - name: 'getBalance', - call: 'eth_getBalance', - params: 2, - inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter], - outputFormatter: formatters.outputBigNumberFormatter -}); - -var getStorageAt = new Method({ - name: 'getStorageAt', - call: 'eth_getStorageAt', - params: 3, - inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter] -}); - -var getCode = new Method({ - name: 'getCode', - call: 'eth_getCode', - params: 2, - inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter] -}); - -var getBlock = new Method({ - name: 'getBlock', - call: blockCall, - params: 2, - inputFormatter: [formatters.inputBlockNumberFormatter, function (val) { return !!val; }], - outputFormatter: formatters.outputBlockFormatter -}); - -var getUncle = new Method({ - name: 'getUncle', - call: uncleCall, - params: 2, - inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex], - outputFormatter: formatters.outputBlockFormatter, - -}); - -var getCompilers = new Method({ - name: 'getCompilers', - call: 'eth_getCompilers', - params: 0 -}); - -var getBlockTransactionCount = new Method({ - name: 'getBlockTransactionCount', - call: getBlockTransactionCountCall, - params: 1, - inputFormatter: [formatters.inputBlockNumberFormatter], - outputFormatter: utils.toDecimal -}); - -var getBlockUncleCount = new Method({ - name: 'getBlockUncleCount', - call: uncleCountCall, - params: 1, - inputFormatter: [formatters.inputBlockNumberFormatter], - outputFormatter: utils.toDecimal -}); - -var getTransaction = new Method({ - name: 'getTransaction', - call: 'eth_getTransactionByHash', - params: 1, - outputFormatter: formatters.outputTransactionFormatter -}); - -var getTransactionFromBlock = new Method({ - name: 'getTransactionFromBlock', - call: transactionFromBlockCall, - params: 2, - inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex], - outputFormatter: formatters.outputTransactionFormatter -}); - -var getTransactionCount = new Method({ - name: 'getTransactionCount', - call: 'eth_getTransactionCount', - params: 2, - inputFormatter: [null, formatters.inputDefaultBlockNumberFormatter], - outputFormatter: utils.toDecimal -}); - -var sendTransaction = new Method({ - name: 'sendTransaction', - call: 'eth_sendTransaction', - params: 1, - inputFormatter: [formatters.inputTransactionFormatter] -}); - -var call = new Method({ - name: 'call', - call: 'eth_call', - params: 2, - inputFormatter: [formatters.inputTransactionFormatter, formatters.inputDefaultBlockNumberFormatter] -}); - -var estimateGas = new Method({ - name: 'estimateGas', - call: 'eth_estimateGas', - params: 1, - inputFormatter: [formatters.inputTransactionFormatter], - outputFormatter: utils.toDecimal -}); - -var compileSolidity = new Method({ - name: 'compile.solidity', - call: 'eth_compileSolidity', - params: 1 -}); - -var compileLLL = new Method({ - name: 'compile.lll', - call: 'eth_compileLLL', - params: 1 -}); - -var compileSerpent = new Method({ - name: 'compile.serpent', - call: 'eth_compileSerpent', - params: 1 -}); - -var submitWork = new Method({ - name: 'submitWork', - call: 'eth_submitWork', - params: 3 -}); - -var getWork = new Method({ - name: 'getWork', - call: 'eth_getWork', - params: 0 -}); - -var methods = [ - getBalance, - getStorageAt, - getCode, - getBlock, - getUncle, - getCompilers, - getBlockTransactionCount, - getBlockUncleCount, - getTransaction, - getTransactionFromBlock, - getTransactionCount, - call, - estimateGas, - sendTransaction, - compileSolidity, - compileLLL, - compileSerpent, - submitWork, - getWork -]; - -/// @returns an array of objects describing web3.eth api properties - - - -var properties = [ - new Property({ - name: 'coinbase', - getter: 'eth_coinbase' - }), - new Property({ - name: 'mining', - getter: 'eth_mining' - }), - new Property({ - name: 'hashrate', - getter: 'eth_hashrate', - outputFormatter: utils.toDecimal - }), - new Property({ - name: 'gasPrice', - getter: 'eth_gasPrice', - outputFormatter: formatters.outputBigNumberFormatter - }), - new Property({ - name: 'accounts', - getter: 'eth_accounts' - }), - new Property({ - name: 'blockNumber', - getter: 'eth_blockNumber', - outputFormatter: utils.toDecimal - }) -]; - -module.exports = { - methods: methods, - properties: properties -}; - - -},{"../utils/utils":7,"./formatters":17,"./method":22,"./property":25}],15:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** - * @file event.js - * @author Marek Kotewicz - * @date 2014 - */ - -var utils = require('../utils/utils'); -var coder = require('../solidity/coder'); -var web3 = require('../web3'); -var formatters = require('./formatters'); -var sha3 = require('../utils/sha3'); - -/** - * This prototype should be used to create event filters - */ -var SolidityEvent = function (json, address) { - this._params = json.inputs; - this._name = utils.transformToFullName(json); - this._address = address; - this._anonymous = json.anonymous; -}; - -/** - * Should be used to get filtered param types - * - * @method types - * @param {Bool} decide if returned typed should be indexed - * @return {Array} array of types - */ -SolidityEvent.prototype.types = function (indexed) { - return this._params.filter(function (i) { - return i.indexed === indexed; - }).map(function (i) { - return i.type; - }); -}; - -/** - * Should be used to get event display name - * - * @method displayName - * @return {String} event display name - */ -SolidityEvent.prototype.displayName = function () { - return utils.extractDisplayName(this._name); -}; - -/** - * Should be used to get event type name - * - * @method typeName - * @return {String} event type name - */ -SolidityEvent.prototype.typeName = function () { - return utils.extractTypeName(this._name); -}; - -/** - * Should be used to get event signature - * - * @method signature - * @return {String} event signature - */ -SolidityEvent.prototype.signature = function () { - return sha3(this._name); -}; - -/** - * Should be used to encode indexed params and options to one final object - * - * @method encode - * @param {Object} indexed - * @param {Object} options - * @return {Object} everything combined together and encoded - */ -SolidityEvent.prototype.encode = function (indexed, options) { - indexed = indexed || {}; - options = options || {}; - var result = {}; - - ['fromBlock', 'toBlock'].filter(function (f) { - return options[f] !== undefined; - }).forEach(function (f) { - result[f] = formatters.inputBlockNumberFormatter(options[f]); - }); - - result.topics = []; - - if (!this._anonymous) { - result.address = this._address; - result.topics.push('0x' + this.signature()); - } - - var indexedTopics = this._params.filter(function (i) { - return i.indexed === true; - }).map(function (i) { - var value = indexed[i.name]; - if (value === undefined || value === null) { - return null; - } - - if (utils.isArray(value)) { - return value.map(function (v) { - return '0x' + coder.encodeParam(i.type, v); - }); - } - return '0x' + coder.encodeParam(i.type, value); - }); - - result.topics = result.topics.concat(indexedTopics); - - return result; -}; - -/** - * Should be used to decode indexed params and options - * - * @method decode - * @param {Object} data - * @return {Object} result object with decoded indexed && not indexed params - */ -SolidityEvent.prototype.decode = function (data) { - - data.data = data.data || ''; - data.topics = data.topics || []; - - var argTopics = this._anonymous ? data.topics : data.topics.slice(1); - var indexedData = argTopics.map(function (topics) { return topics.slice(2); }).join(""); - var indexedParams = coder.decodeParams(this.types(true), indexedData); - - var notIndexedData = data.data.slice(2); - var notIndexedParams = coder.decodeParams(this.types(false), notIndexedData); - - var result = formatters.outputLogFormatter(data); - result.event = this.displayName(); - result.address = data.address; - - result.args = this._params.reduce(function (acc, current) { - acc[current.name] = current.indexed ? indexedParams.shift() : notIndexedParams.shift(); - return acc; - }, {}); - - delete result.data; - delete result.topics; - - return result; -}; - -/** - * Should be used to create new filter object from event - * - * @method execute - * @param {Object} indexed - * @param {Object} options - * @return {Object} filter object - */ -SolidityEvent.prototype.execute = function (indexed, options) { - var o = this.encode(indexed, options); - var formatter = this.decode.bind(this); - return web3.eth.filter(o, undefined, undefined, formatter); -}; - -/** - * Should be used to attach event to contract object - * - * @method attachToContract - * @param {Contract} - */ -SolidityEvent.prototype.attachToContract = function (contract) { - var execute = this.execute.bind(this); - var displayName = this.displayName(); - if (!contract[displayName]) { - contract[displayName] = execute; - } - contract[displayName][this.typeName()] = this.execute.bind(this, contract); -}; - -module.exports = SolidityEvent; - - -},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9,"./formatters":17}],16:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file filter.js - * @authors: - * Jeffrey Wilcke - * Marek Kotewicz - * Marian Oancea - * Fabian Vogelsteller - * Gav Wood - * @date 2014 - */ - -var RequestManager = require('./requestmanager'); -var formatters = require('./formatters'); -var utils = require('../utils/utils'); - -/** -* Converts a given topic to a hex string, but also allows null values. -* -* @param {Mixed} value -* @return {String} -*/ -var toTopic = function(value){ - - if(value === null || typeof value === 'undefined') - return null; - - value = String(value); - - if(value.indexOf('0x') === 0) - return value; - else - return utils.fromAscii(value); -}; - -/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones -/// @param should be string or object -/// @returns options string or object -var getOptions = function (options) { - - if (utils.isString(options)) { - return options; - } - - options = options || {}; - - // make sure topics, get converted to hex - options.topics = options.topics || []; - options.topics = options.topics.map(function(topic){ - return (utils.isArray(topic)) ? topic.map(toTopic) : toTopic(topic); - }); - - // lazy load - return { - topics: options.topics, - to: options.to, - address: options.address, - fromBlock: formatters.inputBlockNumberFormatter(options.fromBlock), - toBlock: formatters.inputBlockNumberFormatter(options.toBlock) - }; -}; - -var Filter = function (options, methods, formatter) { - var implementation = {}; - methods.forEach(function (method) { - method.attachToObject(implementation); - }); - this.options = getOptions(options); - this.implementation = implementation; - this.callbacks = []; - this.formatter = formatter; - this.filterId = this.implementation.newFilter(this.options); -}; - -Filter.prototype.watch = function (callback) { - this.callbacks.push(callback); - var self = this; - - var onMessage = function (error, messages) { - if (error) { - return self.callbacks.forEach(function (callback) { - callback(error); - }); - } - - messages.forEach(function (message) { - message = self.formatter ? self.formatter(message) : message; - self.callbacks.forEach(function (callback) { - callback(null, message); - }); - }); - }; - - // call getFilterLogs on start - if (!utils.isString(this.options)) { - this.get(function (err, messages) { - // don't send all the responses to all the watches again... just to this one - if (err) { - callback(err); - } - - messages.forEach(function (message) { - callback(null, message); - }); - }); - } - - RequestManager.getInstance().startPolling({ - method: this.implementation.poll.call, - params: [this.filterId], - }, this.filterId, onMessage, this.stopWatching.bind(this)); -}; - -Filter.prototype.stopWatching = function () { - RequestManager.getInstance().stopPolling(this.filterId); - this.implementation.uninstallFilter(this.filterId); - this.callbacks = []; -}; - -Filter.prototype.get = function (callback) { - var self = this; - if (utils.isFunction(callback)) { - this.implementation.getLogs(this.filterId, function(err, res){ - if (err) { - callback(err); - } else { - callback(null, res.map(function (log) { - return self.formatter ? self.formatter(log) : log; - })); - } - }); - } else { - var logs = this.implementation.getLogs(this.filterId); - return logs.map(function (log) { - return self.formatter ? self.formatter(log) : log; - }); - } -}; - -module.exports = Filter; - - -},{"../utils/utils":7,"./formatters":17,"./requestmanager":27}],17:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** - * @file formatters.js - * @author Marek Kotewicz - * @author Fabian Vogelsteller - * @date 2015 - */ - -var utils = require('../utils/utils'); -var config = require('../utils/config'); - -/** - * Should the format output to a big number - * - * @method outputBigNumberFormatter - * @param {String|Number|BigNumber} - * @returns {BigNumber} object - */ -var outputBigNumberFormatter = function (number) { - return utils.toBigNumber(number); -}; - -var isPredefinedBlockNumber = function (blockNumber) { - return blockNumber === 'latest' || blockNumber === 'pending' || blockNumber === 'earliest'; -}; - -var inputDefaultBlockNumberFormatter = function (blockNumber) { - if (blockNumber === undefined) { - return config.defaultBlock; - } - return inputBlockNumberFormatter(blockNumber); -}; - -var inputBlockNumberFormatter = function (blockNumber) { - if (blockNumber === undefined) { - return undefined; - } else if (isPredefinedBlockNumber(blockNumber)) { - return blockNumber; - } - return utils.toHex(blockNumber); -}; - -/** - * Formats the input of a transaction and converts all values to HEX - * - * @method inputTransactionFormatter - * @param {Object} transaction options - * @returns object -*/ -var inputTransactionFormatter = function (options){ - - options.from = options.from || config.defaultAccount; - - // make code -> data - if (options.code) { - options.data = options.code; - delete options.code; - } - - ['gasPrice', 'gas', 'value', 'nonce'].filter(function (key) { - return options[key] !== undefined; - }).forEach(function(key){ - options[key] = utils.fromDecimal(options[key]); - }); - - return options; -}; - -/** - * Formats the output of a transaction to its proper values - * - * @method outputTransactionFormatter - * @param {Object} transaction - * @returns {Object} transaction -*/ -var outputTransactionFormatter = function (tx){ - tx.blockNumber = utils.toDecimal(tx.blockNumber); - tx.transactionIndex = utils.toDecimal(tx.transactionIndex); - tx.nonce = utils.toDecimal(tx.nonce); - tx.gas = utils.toDecimal(tx.gas); - tx.gasPrice = utils.toBigNumber(tx.gasPrice); - tx.value = utils.toBigNumber(tx.value); - return tx; -}; - -/** - * Formats the output of a block to its proper values - * - * @method outputBlockFormatter - * @param {Object} block object - * @returns {Object} block object -*/ -var outputBlockFormatter = function(block) { - - // transform to number - block.gasLimit = utils.toDecimal(block.gasLimit); - block.gasUsed = utils.toDecimal(block.gasUsed); - block.size = utils.toDecimal(block.size); - block.timestamp = utils.toDecimal(block.timestamp); - block.number = utils.toDecimal(block.number); - - block.difficulty = utils.toBigNumber(block.difficulty); - block.totalDifficulty = utils.toBigNumber(block.totalDifficulty); - - if (utils.isArray(block.transactions)) { - block.transactions.forEach(function(item){ - if(!utils.isString(item)) - return outputTransactionFormatter(item); - }); - } - - return block; -}; - -/** - * Formats the output of a log - * - * @method outputLogFormatter - * @param {Object} log object - * @returns {Object} log -*/ -var outputLogFormatter = function(log) { - if (log === null) { // 'pending' && 'latest' filters are nulls - return null; - } - - log.blockNumber = utils.toDecimal(log.blockNumber); - log.transactionIndex = utils.toDecimal(log.transactionIndex); - log.logIndex = utils.toDecimal(log.logIndex); - - return log; -}; - -/** - * Formats the input of a whisper post and converts all values to HEX - * - * @method inputPostFormatter - * @param {Object} transaction object - * @returns {Object} -*/ -var inputPostFormatter = function(post) { - - post.payload = utils.toHex(post.payload); - post.ttl = utils.fromDecimal(post.ttl); - post.workToProve = utils.fromDecimal(post.workToProve); - post.priority = utils.fromDecimal(post.priority); - - // fallback - if (!utils.isArray(post.topics)) { - post.topics = post.topics ? [post.topics] : []; - } - - // format the following options - post.topics = post.topics.map(function(topic){ - return utils.fromAscii(topic); - }); - - return post; -}; - -/** - * Formats the output of a received post message - * - * @method outputPostFormatter - * @param {Object} - * @returns {Object} - */ -var outputPostFormatter = function(post){ - - post.expiry = utils.toDecimal(post.expiry); - post.sent = utils.toDecimal(post.sent); - post.ttl = utils.toDecimal(post.ttl); - post.workProved = utils.toDecimal(post.workProved); - post.payloadRaw = post.payload; - post.payload = utils.toAscii(post.payload); - - if (utils.isJson(post.payload)) { - post.payload = JSON.parse(post.payload); - } - - // format the following options - if (!post.topics) { - post.topics = []; - } - post.topics = post.topics.map(function(topic){ - return utils.toAscii(topic); - }); - - return post; -}; - -module.exports = { - inputDefaultBlockNumberFormatter: inputDefaultBlockNumberFormatter, - inputBlockNumberFormatter: inputBlockNumberFormatter, - inputTransactionFormatter: inputTransactionFormatter, - inputPostFormatter: inputPostFormatter, - outputBigNumberFormatter: outputBigNumberFormatter, - outputTransactionFormatter: outputTransactionFormatter, - outputBlockFormatter: outputBlockFormatter, - outputLogFormatter: outputLogFormatter, - outputPostFormatter: outputPostFormatter -}; - - -},{"../utils/config":5,"../utils/utils":7}],18:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** - * @file function.js - * @author Marek Kotewicz - * @date 2015 - */ - -var web3 = require('../web3'); -var coder = require('../solidity/coder'); -var utils = require('../utils/utils'); -var sha3 = require('../utils/sha3'); - -/** - * This prototype should be used to call/sendTransaction to solidity functions - */ -var SolidityFunction = function (json, address) { - this._inputTypes = json.inputs.map(function (i) { - return i.type; - }); - this._outputTypes = json.outputs.map(function (i) { - return i.type; - }); - this._constant = json.constant; - this._name = utils.transformToFullName(json); - this._address = address; -}; - -SolidityFunction.prototype.extractCallback = function (args) { - if (utils.isFunction(args[args.length - 1])) { - return args.pop(); // modify the args array! - } -}; - -/** - * Should be used to create payload from arguments - * - * @method toPayload - * @param {Array} solidity function params - * @param {Object} optional payload options - */ -SolidityFunction.prototype.toPayload = function (args) { - var options = {}; - if (args.length > this._inputTypes.length && utils.isObject(args[args.length -1])) { - options = args[args.length - 1]; - } - options.to = this._address; - options.data = '0x' + this.signature() + coder.encodeParams(this._inputTypes, args); - return options; -}; - -/** - * Should be used to get function signature - * - * @method signature - * @return {String} function signature - */ -SolidityFunction.prototype.signature = function () { - return sha3(this._name).slice(0, 8); -}; - - -SolidityFunction.prototype.unpackOutput = function (output) { - if (!output) { - return; - } - - output = output.length >= 2 ? output.slice(2) : output; - var result = coder.decodeParams(this._outputTypes, output); - return result.length === 1 ? result[0] : result; -}; - -/** - * Calls a contract function. - * - * @method call - * @param {...Object} Contract function arguments - * @param {function} If the last argument is a function, the contract function - * call will be asynchronous, and the callback will be passed the - * error and result. - * @return {String} output bytes - */ -SolidityFunction.prototype.call = function () { - var args = Array.prototype.slice.call(arguments).filter(function (a) {return a !== undefined; }); - var callback = this.extractCallback(args); - var payload = this.toPayload(args); - - if (!callback) { - var output = web3.eth.call(payload); - return this.unpackOutput(output); - } - - var self = this; - web3.eth.call(payload, function (error, output) { - callback(error, self.unpackOutput(output)); - }); -}; - -/** - * Should be used to sendTransaction to solidity function - * - * @method sendTransaction - * @param {Object} options - */ -SolidityFunction.prototype.sendTransaction = function () { - var args = Array.prototype.slice.call(arguments).filter(function (a) {return a !== undefined; }); - var callback = this.extractCallback(args); - var payload = this.toPayload(args); - - if (!callback) { - return web3.eth.sendTransaction(payload); - } - - web3.eth.sendTransaction(payload, callback); -}; - -/** - * Should be used to estimateGas of solidity function - * - * @method estimateGas - * @param {Object} options - */ -SolidityFunction.prototype.estimateGas = function () { - var args = Array.prototype.slice.call(arguments); - var callback = this.extractCallback(args); - var payload = this.toPayload(args); - - if (!callback) { - return web3.eth.estimateGas(payload); - } - - web3.eth.estimateGas(payload, callback); -}; - -/** - * Should be used to get function display name - * - * @method displayName - * @return {String} display name of the function - */ -SolidityFunction.prototype.displayName = function () { - return utils.extractDisplayName(this._name); -}; - -/** - * Should be used to get function type name - * - * @method typeName - * @return {String} type name of the function - */ -SolidityFunction.prototype.typeName = function () { - return utils.extractTypeName(this._name); -}; - -/** - * Should be called to get rpc requests from solidity function - * - * @method request - * @returns {Object} - */ -SolidityFunction.prototype.request = function () { - var args = Array.prototype.slice.call(arguments); - var callback = this.extractCallback(args); - var payload = this.toPayload(args); - var format = this.unpackOutput.bind(this); - - return { - callback: callback, - payload: payload, - format: format - }; -}; - -/** - * Should be called to execute function - * - * @method execute - */ -SolidityFunction.prototype.execute = function () { - var transaction = !this._constant; - - // send transaction - if (transaction) { - return this.sendTransaction.apply(this, Array.prototype.slice.call(arguments)); - } - - // call - return this.call.apply(this, Array.prototype.slice.call(arguments)); -}; - -/** - * Should be called to attach function to contract - * - * @method attachToContract - * @param {Contract} - */ -SolidityFunction.prototype.attachToContract = function (contract) { - var execute = this.execute.bind(this); - execute.request = this.request.bind(this); - execute.call = this.call.bind(this); - execute.sendTransaction = this.sendTransaction.bind(this); - execute.estimateGas = this.estimateGas.bind(this); - var displayName = this.displayName(); - if (!contract[displayName]) { - contract[displayName] = execute; - } - contract[displayName][this.typeName()] = execute; // circular!!!! -}; - -module.exports = SolidityFunction; - - -},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9}],19:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file httpprovider.js - * @authors: - * Marek Kotewicz - * Marian Oancea - * Fabian Vogelsteller - * @date 2014 - */ - -"use strict"; - -var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line -var errors = require('./errors'); - -var HttpProvider = function (host) { - this.host = host || 'http://localhost:8545'; -}; - -HttpProvider.prototype.send = function (payload) { - var request = new XMLHttpRequest(); - - request.open('POST', this.host, false); - - try { - request.send(JSON.stringify(payload)); - } catch(error) { - throw errors.InvalidConnection(this.host); - } - - - // check request.status - // TODO: throw an error here! it cannot silently fail!!! - //if (request.status !== 200) { - //return; - //} - - var result = request.responseText; - - try { - result = JSON.parse(result); - } catch(e) { - throw errors.InvalidResponse(result); - } - - return result; -}; - -HttpProvider.prototype.sendAsync = function (payload, callback) { - var request = new XMLHttpRequest(); - request.onreadystatechange = function() { - if (request.readyState === 4) { - var result = request.responseText; - var error = null; - - try { - result = JSON.parse(result); - } catch(e) { - error = errors.InvalidResponse(result); - } - - callback(error, result); - } - }; - - request.open('POST', this.host, true); - - try { - request.send(JSON.stringify(payload)); - } catch(error) { - callback(errors.InvalidConnection(this.host)); - } -}; - -module.exports = HttpProvider; - - -},{"./errors":13,"xmlhttprequest":4}],20:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** - * @file icap.js - * @author Marek Kotewicz - * @date 2015 - */ - -var utils = require('../utils/utils'); - -/** - * This prototype should be used to extract necessary information from iban address - * - * @param {String} iban - */ -var ICAP = function (iban) { - this._iban = iban; -}; - -/** - * Should be called to check if icap is correct - * - * @method isValid - * @returns {Boolean} true if it is, otherwise false - */ -ICAP.prototype.isValid = function () { - return utils.isIBAN(this._iban); -}; - -/** - * Should be called to check if iban number is direct - * - * @method isDirect - * @returns {Boolean} true if it is, otherwise false - */ -ICAP.prototype.isDirect = function () { - return this._iban.length === 34; -}; - -/** - * Should be called to check if iban number if indirect - * - * @method isIndirect - * @returns {Boolean} true if it is, otherwise false - */ -ICAP.prototype.isIndirect = function () { - return this._iban.length === 20; -}; - -/** - * Should be called to get iban checksum - * Uses the mod-97-10 checksumming protocol (ISO/IEC 7064:2003) - * - * @method checksum - * @returns {String} checksum - */ -ICAP.prototype.checksum = function () { - return this._iban.substr(2, 2); -}; - -/** - * Should be called to get institution identifier - * eg. XREG - * - * @method institution - * @returns {String} institution identifier - */ -ICAP.prototype.institution = function () { - return this.isIndirect() ? this._iban.substr(7, 4) : ''; -}; - -/** - * Should be called to get client identifier within institution - * eg. GAVOFYORK - * - * @method client - * @returns {String} client identifier - */ -ICAP.prototype.client = function () { - return this.isIndirect() ? this._iban.substr(11) : ''; -}; - -/** - * Should be called to get client direct address - * - * @method address - * @returns {String} client direct address - */ -ICAP.prototype.address = function () { - return this.isDirect() ? this._iban.substr(4) : ''; -}; - -module.exports = ICAP; - - -},{"../utils/utils":7}],21:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file jsonrpc.js - * @authors: - * Marek Kotewicz - * @date 2015 - */ - -var Jsonrpc = function () { - // singleton pattern - if (arguments.callee._singletonInstance) { - return arguments.callee._singletonInstance; - } - arguments.callee._singletonInstance = this; - - this.messageId = 1; -}; - -/** - * @return {Jsonrpc} singleton - */ -Jsonrpc.getInstance = function () { - var instance = new Jsonrpc(); - return instance; -}; - -/** - * Should be called to valid json create payload object - * - * @method toPayload - * @param {Function} method of jsonrpc call, required - * @param {Array} params, an array of method params, optional - * @returns {Object} valid jsonrpc payload object - */ -Jsonrpc.prototype.toPayload = function (method, params) { - if (!method) - console.error('jsonrpc method should be specified!'); - - return { - jsonrpc: '2.0', - method: method, - params: params || [], - id: this.messageId++ - }; -}; - -/** - * Should be called to check if jsonrpc response is valid - * - * @method isValidResponse - * @param {Object} - * @returns {Boolean} true if response is valid, otherwise false - */ -Jsonrpc.prototype.isValidResponse = function (response) { - return !!response && - !response.error && - response.jsonrpc === '2.0' && - typeof response.id === 'number' && - response.result !== undefined; // only undefined is not valid json object -}; - -/** - * Should be called to create batch payload object - * - * @method toBatchPayload - * @param {Array} messages, an array of objects with method (required) and params (optional) fields - * @returns {Array} batch payload - */ -Jsonrpc.prototype.toBatchPayload = function (messages) { - var self = this; - return messages.map(function (message) { - return self.toPayload(message.method, message.params); - }); -}; - -module.exports = Jsonrpc; - - -},{}],22:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** - * @file method.js - * @author Marek Kotewicz - * @date 2015 - */ - -var RequestManager = require('./requestmanager'); -var utils = require('../utils/utils'); -var errors = require('./errors'); - -var Method = function (options) { - this.name = options.name; - this.call = options.call; - this.params = options.params || 0; - this.inputFormatter = options.inputFormatter; - this.outputFormatter = options.outputFormatter; -}; - -/** - * Should be used to determine name of the jsonrpc method based on arguments - * - * @method getCall - * @param {Array} arguments - * @return {String} name of jsonrpc method - */ -Method.prototype.getCall = function (args) { - return utils.isFunction(this.call) ? this.call(args) : this.call; -}; - -/** - * Should be used to extract callback from array of arguments. Modifies input param - * - * @method extractCallback - * @param {Array} arguments - * @return {Function|Null} callback, if exists - */ -Method.prototype.extractCallback = function (args) { - if (utils.isFunction(args[args.length - 1])) { - return args.pop(); // modify the args array! - } -}; - -/** - * Should be called to check if the number of arguments is correct - * - * @method validateArgs - * @param {Array} arguments - * @throws {Error} if it is not - */ -Method.prototype.validateArgs = function (args) { - if (args.length !== this.params) { - throw errors.InvalidNumberOfParams(); - } -}; - -/** - * Should be called to format input args of method - * - * @method formatInput - * @param {Array} - * @return {Array} - */ -Method.prototype.formatInput = function (args) { - if (!this.inputFormatter) { - return args; - } - - return this.inputFormatter.map(function (formatter, index) { - return formatter ? formatter(args[index]) : args[index]; - }); -}; - -/** - * Should be called to format output(result) of method - * - * @method formatOutput - * @param {Object} - * @return {Object} - */ -Method.prototype.formatOutput = function (result) { - return this.outputFormatter && result !== null ? this.outputFormatter(result) : result; -}; - -/** - * Should attach function to method - * - * @method attachToObject - * @param {Object} - * @param {Function} - */ -Method.prototype.attachToObject = function (obj) { - var func = this.send.bind(this); - func.request = this.request.bind(this); - func.call = this.call; // that's ugly. filter.js uses it - var name = this.name.split('.'); - if (name.length > 1) { - obj[name[0]] = obj[name[0]] || {}; - obj[name[0]][name[1]] = func; - } else { - obj[name[0]] = func; - } -}; - -/** - * Should create payload from given input args - * - * @method toPayload - * @param {Array} args - * @return {Object} - */ -Method.prototype.toPayload = function (args) { - var call = this.getCall(args); - var callback = this.extractCallback(args); - var params = this.formatInput(args); - this.validateArgs(params); - - return { - method: call, - params: params, - callback: callback - }; -}; - -/** - * Should be called to create pure JSONRPC request which can be used in batch request - * - * @method request - * @param {...} params - * @return {Object} jsonrpc request - */ -Method.prototype.request = function () { - var payload = this.toPayload(Array.prototype.slice.call(arguments)); - payload.format = this.formatOutput.bind(this); - return payload; -}; - -/** - * Should send request to the API - * - * @method send - * @param list of params - * @return result - */ -Method.prototype.send = function () { - var payload = this.toPayload(Array.prototype.slice.call(arguments)); - if (payload.callback) { - var self = this; - return RequestManager.getInstance().sendAsync(payload, function (err, result) { - payload.callback(err, self.formatOutput(result)); - }); - } - return this.formatOutput(RequestManager.getInstance().send(payload)); -}; - -module.exports = Method; - - -},{"../utils/utils":7,"./errors":13,"./requestmanager":27}],23:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** - * @file namereg.js - * @author Marek Kotewicz - * @date 2015 - */ - -var contract = require('./contract'); - -var address = '0xc6d9d2cd449a754c494264e1809c50e34d64562b'; - -var abi = [ - {"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"name","outputs":[{"name":"o_name","type":"bytes32"}],"type":"function"}, - {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"}, - {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"content","outputs":[{"name":"","type":"bytes32"}],"type":"function"}, - {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"addr","outputs":[{"name":"","type":"address"}],"type":"function"}, - {"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserve","outputs":[],"type":"function"}, - {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"subRegistrar","outputs":[{"name":"o_subRegistrar","type":"address"}],"type":"function"}, - {"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_newOwner","type":"address"}],"name":"transfer","outputs":[],"type":"function"}, - {"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_registrar","type":"address"}],"name":"setSubRegistrar","outputs":[],"type":"function"}, - {"constant":false,"inputs":[],"name":"Registrar","outputs":[],"type":"function"}, - {"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_a","type":"address"},{"name":"_primary","type":"bool"}],"name":"setAddress","outputs":[],"type":"function"}, - {"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_content","type":"bytes32"}],"name":"setContent","outputs":[],"type":"function"}, - {"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"disown","outputs":[],"type":"function"}, - {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"register","outputs":[{"name":"","type":"address"}],"type":"function"}, - {"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"}],"name":"Changed","type":"event"}, - {"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"addr","type":"address"}],"name":"PrimaryChanged","type":"event"} -]; - -module.exports = contract(abi).at(address); - - -},{"./contract":11}],24:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file eth.js - * @authors: - * Marek Kotewicz - * @date 2015 - */ - -var utils = require('../utils/utils'); -var Property = require('./property'); - -/// @returns an array of objects describing web3.eth api methods -var methods = [ -]; - -/// @returns an array of objects describing web3.eth api properties -var properties = [ - new Property({ - name: 'listening', - getter: 'net_listening' - }), - new Property({ - name: 'peerCount', - getter: 'net_peerCount', - outputFormatter: utils.toDecimal - }) -]; - - -module.exports = { - methods: methods, - properties: properties -}; - - -},{"../utils/utils":7,"./property":25}],25:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** - * @file property.js - * @author Fabian Vogelsteller - * @author Marek Kotewicz - * @date 2015 - */ - -var RequestManager = require('./requestmanager'); - -var Property = function (options) { - this.name = options.name; - this.getter = options.getter; - this.setter = options.setter; - this.outputFormatter = options.outputFormatter; - this.inputFormatter = options.inputFormatter; -}; - -/** - * Should be called to format input args of method - * - * @method formatInput - * @param {Array} - * @return {Array} - */ -Property.prototype.formatInput = function (arg) { - return this.inputFormatter ? this.inputFormatter(arg) : arg; -}; - -/** - * Should be called to format output(result) of method - * - * @method formatOutput - * @param {Object} - * @return {Object} - */ -Property.prototype.formatOutput = function (result) { - return this.outputFormatter && result !== null ? this.outputFormatter(result) : result; -}; - -/** - * Should attach function to method - * - * @method attachToObject - * @param {Object} - * @param {Function} - */ -Property.prototype.attachToObject = function (obj) { - var proto = { - get: this.get.bind(this), - }; - - var names = this.name.split('.'); - var name = names[0]; - if (names.length > 1) { - obj[names[0]] = obj[names[0]] || {}; - obj = obj[names[0]]; - name = names[1]; - } - - Object.defineProperty(obj, name, proto); - - var toAsyncName = function (prefix, name) { - return prefix + name.charAt(0).toUpperCase() + name.slice(1); - }; - - obj[toAsyncName('get', name)] = this.getAsync.bind(this); -}; - -/** - * Should be used to get value of the property - * - * @method get - * @return {Object} value of the property - */ -Property.prototype.get = function () { - return this.formatOutput(RequestManager.getInstance().send({ - method: this.getter - })); -}; - -/** - * Should be used to asynchrounously get value of property - * - * @method getAsync - * @param {Function} - */ -Property.prototype.getAsync = function (callback) { - var self = this; - RequestManager.getInstance().sendAsync({ - method: this.getter - }, function (err, result) { - if (err) { - return callback(err); - } - callback(err, self.formatOutput(result)); - }); -}; - -module.exports = Property; - - -},{"./requestmanager":27}],26:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file qtsync.js - * @authors: - * Marek Kotewicz - * Marian Oancea - * @date 2014 - */ - -var QtSyncProvider = function () { -}; - -QtSyncProvider.prototype.send = function (payload) { - var result = navigator.qt.callMethod(JSON.stringify(payload)); - return JSON.parse(result); -}; - -module.exports = QtSyncProvider; - - -},{}],27:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** - * @file requestmanager.js - * @author Jeffrey Wilcke - * @author Marek Kotewicz - * @author Marian Oancea - * @author Fabian Vogelsteller - * @author Gav Wood - * @date 2014 - */ - -var Jsonrpc = require('./jsonrpc'); -var utils = require('../utils/utils'); -var c = require('../utils/config'); -var errors = require('./errors'); - -/** - * It's responsible for passing messages to providers - * It's also responsible for polling the ethereum node for incoming messages - * Default poll timeout is 1 second - * Singleton - */ -var RequestManager = function (provider) { - // singleton pattern - if (arguments.callee._singletonInstance) { - return arguments.callee._singletonInstance; - } - arguments.callee._singletonInstance = this; - - this.provider = provider; - this.polls = []; - this.timeout = null; - this.poll(); -}; - -/** - * @return {RequestManager} singleton - */ -RequestManager.getInstance = function () { - var instance = new RequestManager(); - return instance; -}; - -/** - * Should be used to synchronously send request - * - * @method send - * @param {Object} data - * @return {Object} - */ -RequestManager.prototype.send = function (data) { - if (!this.provider) { - console.error(errors.InvalidProvider()); - return null; - } - - var payload = Jsonrpc.getInstance().toPayload(data.method, data.params); - var result = this.provider.send(payload); - - if (!Jsonrpc.getInstance().isValidResponse(result)) { - throw errors.InvalidResponse(result); - } - - return result.result; -}; - -/** - * Should be used to asynchronously send request - * - * @method sendAsync - * @param {Object} data - * @param {Function} callback - */ -RequestManager.prototype.sendAsync = function (data, callback) { - if (!this.provider) { - return callback(errors.InvalidProvider()); - } - - var payload = Jsonrpc.getInstance().toPayload(data.method, data.params); - this.provider.sendAsync(payload, function (err, result) { - if (err) { - return callback(err); - } - - if (!Jsonrpc.getInstance().isValidResponse(result)) { - return callback(errors.InvalidResponse(result)); - } - - callback(null, result.result); - }); -}; - -/** - * Should be called to asynchronously send batch request - * - * @method sendBatch - * @param {Array} batch data - * @param {Function} callback - */ -RequestManager.prototype.sendBatch = function (data, callback) { - if (!this.provider) { - return callback(errors.InvalidProvider()); - } - - var payload = Jsonrpc.getInstance().toBatchPayload(data); - - this.provider.sendAsync(payload, function (err, results) { - if (err) { - return callback(err); - } - - if (!utils.isArray(results)) { - return callback(errors.InvalidResponse(results)); - } - - callback(err, results); - }); -}; - -/** - * Should be used to set provider of request manager - * - * @method setProvider - * @param {Object} - */ -RequestManager.prototype.setProvider = function (p) { - this.provider = p; -}; - -/*jshint maxparams:4 */ - -/** - * Should be used to start polling - * - * @method startPolling - * @param {Object} data - * @param {Number} pollId - * @param {Function} callback - * @param {Function} uninstall - * - * @todo cleanup number of params - */ -RequestManager.prototype.startPolling = function (data, pollId, callback, uninstall) { - this.polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall}); -}; -/*jshint maxparams:3 */ - -/** - * Should be used to stop polling for filter with given id - * - * @method stopPolling - * @param {Number} pollId - */ -RequestManager.prototype.stopPolling = function (pollId) { - for (var i = this.polls.length; i--;) { - var poll = this.polls[i]; - if (poll.id === pollId) { - this.polls.splice(i, 1); - } - } -}; - -/** - * Should be called to reset polling mechanism of request manager - * - * @method reset - */ -RequestManager.prototype.reset = function () { - this.polls.forEach(function (poll) { - poll.uninstall(poll.id); - }); - this.polls = []; - - if (this.timeout) { - clearTimeout(this.timeout); - this.timeout = null; - } - this.poll(); -}; - -/** - * Should be called to poll for changes on filter with given id - * - * @method poll - */ -RequestManager.prototype.poll = function () { - this.timeout = setTimeout(this.poll.bind(this), c.ETH_POLLING_TIMEOUT); - - if (!this.polls.length) { - return; - } - - if (!this.provider) { - console.error(errors.InvalidProvider()); - return; - } - - var payload = Jsonrpc.getInstance().toBatchPayload(this.polls.map(function (data) { - return data.data; - })); - - var self = this; - this.provider.sendAsync(payload, function (error, results) { - // TODO: console log? - if (error) { - return; - } - - if (!utils.isArray(results)) { - throw errors.InvalidResponse(results); - } - - results.map(function (result, index) { - result.callback = self.polls[index].callback; - return result; - }).filter(function (result) { - var valid = Jsonrpc.getInstance().isValidResponse(result); - if (!valid) { - result.callback(errors.InvalidResponse(result)); - } - return valid; - }).filter(function (result) { - return utils.isArray(result.result) && result.result.length > 0; - }).forEach(function (result) { - result.callback(null, result.result); - }); - }); -}; - -module.exports = RequestManager; - - -},{"../utils/config":5,"../utils/utils":7,"./errors":13,"./jsonrpc":21}],28:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file shh.js - * @authors: - * Marek Kotewicz - * @date 2015 - */ - -var Method = require('./method'); -var formatters = require('./formatters'); - -var post = new Method({ - name: 'post', - call: 'shh_post', - params: 1, - inputFormatter: [formatters.inputPostFormatter] -}); - -var newIdentity = new Method({ - name: 'newIdentity', - call: 'shh_newIdentity', - params: 0 -}); - -var hasIdentity = new Method({ - name: 'hasIdentity', - call: 'shh_hasIdentity', - params: 1 -}); - -var newGroup = new Method({ - name: 'newGroup', - call: 'shh_newGroup', - params: 0 -}); - -var addToGroup = new Method({ - name: 'addToGroup', - call: 'shh_addToGroup', - params: 0 -}); - -var methods = [ - post, - newIdentity, - hasIdentity, - newGroup, - addToGroup -]; - -module.exports = { - methods: methods -}; - - -},{"./formatters":17,"./method":22}],29:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** - * @file transfer.js - * @author Marek Kotewicz - * @date 2015 - */ - -var web3 = require('../web3'); -var ICAP = require('./icap'); -var namereg = require('./namereg'); -var contract = require('./contract'); - -/** - * Should be used to make ICAP transfer - * - * @method transfer - * @param {String} iban number - * @param {String} from (address) - * @param {Value} value to be tranfered - * @param {Function} callback, callback - */ -var transfer = function (from, iban, value, callback) { - var icap = new ICAP(iban); - if (!icap.isValid()) { - throw new Error('invalid iban address'); - } - - if (icap.isDirect()) { - return transferToAddress(from, icap.address(), value, callback); - } - - if (!callback) { - var address = namereg.addr(icap.institution()); - return deposit(from, address, value, icap.client()); - } - - namereg.addr(icap.insitution(), function (err, address) { - return deposit(from, address, value, icap.client(), callback); - }); - -}; - -/** - * Should be used to transfer funds to certain address - * - * @method transferToAddress - * @param {String} address - * @param {String} from (address) - * @param {Value} value to be tranfered - * @param {Function} callback, callback - */ -var transferToAddress = function (from, address, value, callback) { - return web3.eth.sendTransaction({ - address: address, - from: from, - value: value - }, callback); -}; - -/** - * Should be used to deposit funds to generic Exchange contract (must implement deposit(bytes32) method!) - * - * @method deposit - * @param {String} address - * @param {String} from (address) - * @param {Value} value to be tranfered - * @param {String} client unique identifier - * @param {Function} callback, callback - */ -var deposit = function (from, address, value, client, callback) { - var abi = [{"constant":false,"inputs":[{"name":"name","type":"bytes32"}],"name":"deposit","outputs":[],"type":"function"}]; - return contract(abi).at(address).deposit(client, { - from: from, - value: value - }, callback); -}; - -module.exports = transfer; - - -},{"../web3":9,"./contract":11,"./icap":20,"./namereg":23}],30:[function(require,module,exports){ -/* - This file is part of ethereum.js. - - ethereum.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - ethereum.js 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with ethereum.js. If not, see . -*/ -/** @file watches.js - * @authors: - * Marek Kotewicz - * @date 2015 - */ - -var Method = require('./method'); - -/// @returns an array of objects describing web3.eth.filter api methods -var eth = function () { - var newFilterCall = function (args) { - var type = args[0]; - - switch(type) { - case 'latest': - args.pop(); - this.params = 0; - return 'eth_newBlockFilter'; - case 'pending': - args.pop(); - this.params = 0; - return 'eth_newPendingTransactionFilter'; - default: - return 'eth_newFilter'; - } - }; - - var newFilter = new Method({ - name: 'newFilter', - call: newFilterCall, - params: 1 - }); - - var uninstallFilter = new Method({ - name: 'uninstallFilter', - call: 'eth_uninstallFilter', - params: 1 - }); - - var getLogs = new Method({ - name: 'getLogs', - call: 'eth_getFilterLogs', - params: 1 - }); - - var poll = new Method({ - name: 'poll', - call: 'eth_getFilterChanges', - params: 1 - }); - - return [ - newFilter, - uninstallFilter, - getLogs, - poll - ]; -}; - -/// @returns an array of objects describing web3.shh.watch api methods -var shh = function () { - var newFilter = new Method({ - name: 'newFilter', - call: 'shh_newFilter', - params: 1 - }); - - var uninstallFilter = new Method({ - name: 'uninstallFilter', - call: 'shh_uninstallFilter', - params: 1 - }); - - var getLogs = new Method({ - name: 'getLogs', - call: 'shh_getMessages', - params: 1 - }); - - var poll = new Method({ - name: 'poll', - call: 'shh_getFilterChanges', - params: 1 - }); - - return [ - newFilter, - uninstallFilter, - getLogs, - poll - ]; -}; - -module.exports = { - eth: eth, - shh: shh -}; - - -},{"./method":22}],31:[function(require,module,exports){ - -},{}],32:[function(require,module,exports){ -;(function (root, factory) { - if (typeof exports === "object") { - // CommonJS - module.exports = exports = factory(); - } - else if (typeof define === "function" && define.amd) { - // AMD - define([], factory); - } - else { - // Global (browser) - root.CryptoJS = factory(); - } -}(this, function () { - - /** - * CryptoJS core components. - */ - var CryptoJS = CryptoJS || (function (Math, undefined) { - /** - * CryptoJS namespace. - */ - var C = {}; - - /** - * Library namespace. - */ - var C_lib = C.lib = {}; - - /** - * Base object for prototypal inheritance. - */ - var Base = C_lib.Base = (function () { - function F() {} - - return { - /** - * Creates a new object that inherits from this object. - * - * @param {Object} overrides Properties to copy into the new object. - * - * @return {Object} The new object. - * - * @static - * - * @example - * - * var MyType = CryptoJS.lib.Base.extend({ - * field: 'value', - * - * method: function () { - * } - * }); - */ - extend: function (overrides) { - // Spawn - F.prototype = this; - var subtype = new F(); - - // Augment - if (overrides) { - subtype.mixIn(overrides); - } - - // Create default initializer - if (!subtype.hasOwnProperty('init')) { - subtype.init = function () { - subtype.$super.init.apply(this, arguments); - }; - } - - // Initializer's prototype is the subtype object - subtype.init.prototype = subtype; - - // Reference supertype - subtype.$super = this; - - return subtype; - }, - - /** - * Extends this object and runs the init method. - * Arguments to create() will be passed to init(). - * - * @return {Object} The new object. - * - * @static - * - * @example - * - * var instance = MyType.create(); - */ - create: function () { - var instance = this.extend(); - instance.init.apply(instance, arguments); - - return instance; - }, - - /** - * Initializes a newly created object. - * Override this method to add some logic when your objects are created. - * - * @example - * - * var MyType = CryptoJS.lib.Base.extend({ - * init: function () { - * // ... - * } - * }); - */ - init: function () { - }, - - /** - * Copies properties into this object. - * - * @param {Object} properties The properties to mix in. - * - * @example - * - * MyType.mixIn({ - * field: 'value' - * }); - */ - mixIn: function (properties) { - for (var propertyName in properties) { - if (properties.hasOwnProperty(propertyName)) { - this[propertyName] = properties[propertyName]; - } - } - - // IE won't copy toString using the loop above - if (properties.hasOwnProperty('toString')) { - this.toString = properties.toString; - } - }, - - /** - * Creates a copy of this object. - * - * @return {Object} The clone. - * - * @example - * - * var clone = instance.clone(); - */ - clone: function () { - return this.init.prototype.extend(this); - } - }; - }()); - - /** - * An array of 32-bit words. - * - * @property {Array} words The array of 32-bit words. - * @property {number} sigBytes The number of significant bytes in this word array. - */ - var WordArray = C_lib.WordArray = Base.extend({ - /** - * Initializes a newly created word array. - * - * @param {Array} words (Optional) An array of 32-bit words. - * @param {number} sigBytes (Optional) The number of significant bytes in the words. - * - * @example - * - * var wordArray = CryptoJS.lib.WordArray.create(); - * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]); - * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6); - */ - init: function (words, sigBytes) { - words = this.words = words || []; - - if (sigBytes != undefined) { - this.sigBytes = sigBytes; - } else { - this.sigBytes = words.length * 4; - } - }, - - /** - * Converts this word array to a string. - * - * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex - * - * @return {string} The stringified word array. - * - * @example - * - * var string = wordArray + ''; - * var string = wordArray.toString(); - * var string = wordArray.toString(CryptoJS.enc.Utf8); - */ - toString: function (encoder) { - return (encoder || Hex).stringify(this); - }, - - /** - * Concatenates a word array to this word array. - * - * @param {WordArray} wordArray The word array to append. - * - * @return {WordArray} This word array. - * - * @example - * - * wordArray1.concat(wordArray2); - */ - concat: function (wordArray) { - // Shortcuts - var thisWords = this.words; - var thatWords = wordArray.words; - var thisSigBytes = this.sigBytes; - var thatSigBytes = wordArray.sigBytes; - - // Clamp excess bits - this.clamp(); - - // Concat - if (thisSigBytes % 4) { - // Copy one byte at a time - for (var i = 0; i < thatSigBytes; i++) { - var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; - thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8); - } - } else { - // Copy one word at a time - for (var i = 0; i < thatSigBytes; i += 4) { - thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2]; - } - } - this.sigBytes += thatSigBytes; - - // Chainable - return this; - }, - - /** - * Removes insignificant bits. - * - * @example - * - * wordArray.clamp(); - */ - clamp: function () { - // Shortcuts - var words = this.words; - var sigBytes = this.sigBytes; - - // Clamp - words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8); - words.length = Math.ceil(sigBytes / 4); - }, - - /** - * Creates a copy of this word array. - * - * @return {WordArray} The clone. - * - * @example - * - * var clone = wordArray.clone(); - */ - clone: function () { - var clone = Base.clone.call(this); - clone.words = this.words.slice(0); - - return clone; - }, - - /** - * Creates a word array filled with random bytes. - * - * @param {number} nBytes The number of random bytes to generate. - * - * @return {WordArray} The random word array. - * - * @static - * - * @example - * - * var wordArray = CryptoJS.lib.WordArray.random(16); - */ - random: function (nBytes) { - var words = []; - - var r = (function (m_w) { - var m_w = m_w; - var m_z = 0x3ade68b1; - var mask = 0xffffffff; - - return function () { - m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask; - m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask; - var result = ((m_z << 0x10) + m_w) & mask; - result /= 0x100000000; - result += 0.5; - return result * (Math.random() > .5 ? 1 : -1); - } - }); - - for (var i = 0, rcache; i < nBytes; i += 4) { - var _r = r((rcache || Math.random()) * 0x100000000); - - rcache = _r() * 0x3ade67b7; - words.push((_r() * 0x100000000) | 0); - } - - return new WordArray.init(words, nBytes); - } - }); - - /** - * Encoder namespace. - */ - var C_enc = C.enc = {}; - - /** - * Hex encoding strategy. - */ - var Hex = C_enc.Hex = { - /** - * Converts a word array to a hex string. - * - * @param {WordArray} wordArray The word array. - * - * @return {string} The hex string. - * - * @static - * - * @example - * - * var hexString = CryptoJS.enc.Hex.stringify(wordArray); - */ - stringify: function (wordArray) { - // Shortcuts - var words = wordArray.words; - var sigBytes = wordArray.sigBytes; - - // Convert - var hexChars = []; - for (var i = 0; i < sigBytes; i++) { - var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; - hexChars.push((bite >>> 4).toString(16)); - hexChars.push((bite & 0x0f).toString(16)); - } - - return hexChars.join(''); - }, - - /** - * Converts a hex string to a word array. - * - * @param {string} hexStr The hex string. - * - * @return {WordArray} The word array. - * - * @static - * - * @example - * - * var wordArray = CryptoJS.enc.Hex.parse(hexString); - */ - parse: function (hexStr) { - // Shortcut - var hexStrLength = hexStr.length; - - // Convert - var words = []; - for (var i = 0; i < hexStrLength; i += 2) { - words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4); - } - - return new WordArray.init(words, hexStrLength / 2); - } - }; - - /** - * Latin1 encoding strategy. - */ - var Latin1 = C_enc.Latin1 = { - /** - * Converts a word array to a Latin1 string. - * - * @param {WordArray} wordArray The word array. - * - * @return {string} The Latin1 string. - * - * @static - * - * @example - * - * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray); - */ - stringify: function (wordArray) { - // Shortcuts - var words = wordArray.words; - var sigBytes = wordArray.sigBytes; - - // Convert - var latin1Chars = []; - for (var i = 0; i < sigBytes; i++) { - var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; - latin1Chars.push(String.fromCharCode(bite)); - } - - return latin1Chars.join(''); - }, - - /** - * Converts a Latin1 string to a word array. - * - * @param {string} latin1Str The Latin1 string. - * - * @return {WordArray} The word array. - * - * @static - * - * @example - * - * var wordArray = CryptoJS.enc.Latin1.parse(latin1String); - */ - parse: function (latin1Str) { - // Shortcut - var latin1StrLength = latin1Str.length; - - // Convert - var words = []; - for (var i = 0; i < latin1StrLength; i++) { - words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8); - } - - return new WordArray.init(words, latin1StrLength); - } - }; - - /** - * UTF-8 encoding strategy. - */ - var Utf8 = C_enc.Utf8 = { - /** - * Converts a word array to a UTF-8 string. - * - * @param {WordArray} wordArray The word array. - * - * @return {string} The UTF-8 string. - * - * @static - * - * @example - * - * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray); - */ - stringify: function (wordArray) { - try { - return decodeURIComponent(escape(Latin1.stringify(wordArray))); - } catch (e) { - throw new Error('Malformed UTF-8 data'); - } - }, - - /** - * Converts a UTF-8 string to a word array. - * - * @param {string} utf8Str The UTF-8 string. - * - * @return {WordArray} The word array. - * - * @static - * - * @example - * - * var wordArray = CryptoJS.enc.Utf8.parse(utf8String); - */ - parse: function (utf8Str) { - return Latin1.parse(unescape(encodeURIComponent(utf8Str))); - } - }; - - /** - * Abstract buffered block algorithm template. - * - * The property blockSize must be implemented in a concrete subtype. - * - * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0 - */ - var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({ - /** - * Resets this block algorithm's data buffer to its initial state. - * - * @example - * - * bufferedBlockAlgorithm.reset(); - */ - reset: function () { - // Initial values - this._data = new WordArray.init(); - this._nDataBytes = 0; - }, - - /** - * Adds new data to this block algorithm's buffer. - * - * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8. - * - * @example - * - * bufferedBlockAlgorithm._append('data'); - * bufferedBlockAlgorithm._append(wordArray); - */ - _append: function (data) { - // Convert string to WordArray, else assume WordArray already - if (typeof data == 'string') { - data = Utf8.parse(data); - } - - // Append - this._data.concat(data); - this._nDataBytes += data.sigBytes; - }, - - /** - * Processes available data blocks. - * - * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype. - * - * @param {boolean} doFlush Whether all blocks and partial blocks should be processed. - * - * @return {WordArray} The processed data. - * - * @example - * - * var processedData = bufferedBlockAlgorithm._process(); - * var processedData = bufferedBlockAlgorithm._process(!!'flush'); - */ - _process: function (doFlush) { - // Shortcuts - var data = this._data; - var dataWords = data.words; - var dataSigBytes = data.sigBytes; - var blockSize = this.blockSize; - var blockSizeBytes = blockSize * 4; - - // Count blocks ready - var nBlocksReady = dataSigBytes / blockSizeBytes; - if (doFlush) { - // Round up to include partial blocks - nBlocksReady = Math.ceil(nBlocksReady); - } else { - // Round down to include only full blocks, - // less the number of blocks that must remain in the buffer - nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0); - } - - // Count words ready - var nWordsReady = nBlocksReady * blockSize; - - // Count bytes ready - var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes); - - // Process blocks - if (nWordsReady) { - for (var offset = 0; offset < nWordsReady; offset += blockSize) { - // Perform concrete-algorithm logic - this._doProcessBlock(dataWords, offset); - } - - // Remove processed words - var processedWords = dataWords.splice(0, nWordsReady); - data.sigBytes -= nBytesReady; - } - - // Return processed words - return new WordArray.init(processedWords, nBytesReady); - }, - - /** - * Creates a copy of this object. - * - * @return {Object} The clone. - * - * @example - * - * var clone = bufferedBlockAlgorithm.clone(); - */ - clone: function () { - var clone = Base.clone.call(this); - clone._data = this._data.clone(); - - return clone; - }, - - _minBufferSize: 0 - }); - - /** - * Abstract hasher template. - * - * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits) - */ - var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({ - /** - * Configuration options. - */ - cfg: Base.extend(), - - /** - * Initializes a newly created hasher. - * - * @param {Object} cfg (Optional) The configuration options to use for this hash computation. - * - * @example - * - * var hasher = CryptoJS.algo.SHA256.create(); - */ - init: function (cfg) { - // Apply config defaults - this.cfg = this.cfg.extend(cfg); - - // Set initial values - this.reset(); - }, - - /** - * Resets this hasher to its initial state. - * - * @example - * - * hasher.reset(); - */ - reset: function () { - // Reset data buffer - BufferedBlockAlgorithm.reset.call(this); - - // Perform concrete-hasher logic - this._doReset(); - }, - - /** - * Updates this hasher with a message. - * - * @param {WordArray|string} messageUpdate The message to append. - * - * @return {Hasher} This hasher. - * - * @example - * - * hasher.update('message'); - * hasher.update(wordArray); - */ - update: function (messageUpdate) { - // Append - this._append(messageUpdate); - - // Update the hash - this._process(); - - // Chainable - return this; - }, - - /** - * Finalizes the hash computation. - * Note that the finalize operation is effectively a destructive, read-once operation. - * - * @param {WordArray|string} messageUpdate (Optional) A final message update. - * - * @return {WordArray} The hash. - * - * @example - * - * var hash = hasher.finalize(); - * var hash = hasher.finalize('message'); - * var hash = hasher.finalize(wordArray); - */ - finalize: function (messageUpdate) { - // Final message update - if (messageUpdate) { - this._append(messageUpdate); - } - - // Perform concrete-hasher logic - var hash = this._doFinalize(); - - return hash; - }, - - blockSize: 512/32, - - /** - * Creates a shortcut function to a hasher's object interface. - * - * @param {Hasher} hasher The hasher to create a helper for. - * - * @return {Function} The shortcut function. - * - * @static - * - * @example - * - * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256); - */ - _createHelper: function (hasher) { - return function (message, cfg) { - return new hasher.init(cfg).finalize(message); - }; - }, - - /** - * Creates a shortcut function to the HMAC's object interface. - * - * @param {Hasher} hasher The hasher to use in this HMAC helper. - * - * @return {Function} The shortcut function. - * - * @static - * - * @example - * - * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256); - */ - _createHmacHelper: function (hasher) { - return function (message, key) { - return new C_algo.HMAC.init(hasher, key).finalize(message); - }; - } - }); - - /** - * Algorithm namespace. - */ - var C_algo = C.algo = {}; - - return C; - }(Math)); - - - return CryptoJS; - -})); -},{}],33:[function(require,module,exports){ -;(function (root, factory, undef) { - if (typeof exports === "object") { - // CommonJS - module.exports = exports = factory(require("./core"), require("./x64-core")); - } - else if (typeof define === "function" && define.amd) { - // AMD - define(["./core", "./x64-core"], factory); - } - else { - // Global (browser) - factory(root.CryptoJS); - } -}(this, function (CryptoJS) { - - (function (Math) { - // Shortcuts - var C = CryptoJS; - var C_lib = C.lib; - var WordArray = C_lib.WordArray; - var Hasher = C_lib.Hasher; - var C_x64 = C.x64; - var X64Word = C_x64.Word; - var C_algo = C.algo; - - // Constants tables - var RHO_OFFSETS = []; - var PI_INDEXES = []; - var ROUND_CONSTANTS = []; - - // Compute Constants - (function () { - // Compute rho offset constants - var x = 1, y = 0; - for (var t = 0; t < 24; t++) { - RHO_OFFSETS[x + 5 * y] = ((t + 1) * (t + 2) / 2) % 64; - - var newX = y % 5; - var newY = (2 * x + 3 * y) % 5; - x = newX; - y = newY; - } - - // Compute pi index constants - for (var x = 0; x < 5; x++) { - for (var y = 0; y < 5; y++) { - PI_INDEXES[x + 5 * y] = y + ((2 * x + 3 * y) % 5) * 5; - } - } - - // Compute round constants - var LFSR = 0x01; - for (var i = 0; i < 24; i++) { - var roundConstantMsw = 0; - var roundConstantLsw = 0; - - for (var j = 0; j < 7; j++) { - if (LFSR & 0x01) { - var bitPosition = (1 << j) - 1; - if (bitPosition < 32) { - roundConstantLsw ^= 1 << bitPosition; - } else /* if (bitPosition >= 32) */ { - roundConstantMsw ^= 1 << (bitPosition - 32); - } - } - - // Compute next LFSR - if (LFSR & 0x80) { - // Primitive polynomial over GF(2): x^8 + x^6 + x^5 + x^4 + 1 - LFSR = (LFSR << 1) ^ 0x71; - } else { - LFSR <<= 1; - } - } - - ROUND_CONSTANTS[i] = X64Word.create(roundConstantMsw, roundConstantLsw); - } - }()); - - // Reusable objects for temporary values - var T = []; - (function () { - for (var i = 0; i < 25; i++) { - T[i] = X64Word.create(); - } - }()); - - /** - * SHA-3 hash algorithm. - */ - var SHA3 = C_algo.SHA3 = Hasher.extend({ - /** - * Configuration options. - * - * @property {number} outputLength - * The desired number of bits in the output hash. - * Only values permitted are: 224, 256, 384, 512. - * Default: 512 - */ - cfg: Hasher.cfg.extend({ - outputLength: 512 - }), - - _doReset: function () { - var state = this._state = [] - for (var i = 0; i < 25; i++) { - state[i] = new X64Word.init(); - } - - this.blockSize = (1600 - 2 * this.cfg.outputLength) / 32; - }, - - _doProcessBlock: function (M, offset) { - // Shortcuts - var state = this._state; - var nBlockSizeLanes = this.blockSize / 2; - - // Absorb - for (var i = 0; i < nBlockSizeLanes; i++) { - // Shortcuts - var M2i = M[offset + 2 * i]; - var M2i1 = M[offset + 2 * i + 1]; - - // Swap endian - M2i = ( - (((M2i << 8) | (M2i >>> 24)) & 0x00ff00ff) | - (((M2i << 24) | (M2i >>> 8)) & 0xff00ff00) - ); - M2i1 = ( - (((M2i1 << 8) | (M2i1 >>> 24)) & 0x00ff00ff) | - (((M2i1 << 24) | (M2i1 >>> 8)) & 0xff00ff00) - ); - - // Absorb message into state - var lane = state[i]; - lane.high ^= M2i1; - lane.low ^= M2i; - } - - // Rounds - for (var round = 0; round < 24; round++) { - // Theta - for (var x = 0; x < 5; x++) { - // Mix column lanes - var tMsw = 0, tLsw = 0; - for (var y = 0; y < 5; y++) { - var lane = state[x + 5 * y]; - tMsw ^= lane.high; - tLsw ^= lane.low; - } - - // Temporary values - var Tx = T[x]; - Tx.high = tMsw; - Tx.low = tLsw; - } - for (var x = 0; x < 5; x++) { - // Shortcuts - var Tx4 = T[(x + 4) % 5]; - var Tx1 = T[(x + 1) % 5]; - var Tx1Msw = Tx1.high; - var Tx1Lsw = Tx1.low; - - // Mix surrounding columns - var tMsw = Tx4.high ^ ((Tx1Msw << 1) | (Tx1Lsw >>> 31)); - var tLsw = Tx4.low ^ ((Tx1Lsw << 1) | (Tx1Msw >>> 31)); - for (var y = 0; y < 5; y++) { - var lane = state[x + 5 * y]; - lane.high ^= tMsw; - lane.low ^= tLsw; - } - } - - // Rho Pi - for (var laneIndex = 1; laneIndex < 25; laneIndex++) { - // Shortcuts - var lane = state[laneIndex]; - var laneMsw = lane.high; - var laneLsw = lane.low; - var rhoOffset = RHO_OFFSETS[laneIndex]; - - // Rotate lanes - if (rhoOffset < 32) { - var tMsw = (laneMsw << rhoOffset) | (laneLsw >>> (32 - rhoOffset)); - var tLsw = (laneLsw << rhoOffset) | (laneMsw >>> (32 - rhoOffset)); - } else /* if (rhoOffset >= 32) */ { - var tMsw = (laneLsw << (rhoOffset - 32)) | (laneMsw >>> (64 - rhoOffset)); - var tLsw = (laneMsw << (rhoOffset - 32)) | (laneLsw >>> (64 - rhoOffset)); - } - - // Transpose lanes - var TPiLane = T[PI_INDEXES[laneIndex]]; - TPiLane.high = tMsw; - TPiLane.low = tLsw; - } - - // Rho pi at x = y = 0 - var T0 = T[0]; - var state0 = state[0]; - T0.high = state0.high; - T0.low = state0.low; - - // Chi - for (var x = 0; x < 5; x++) { - for (var y = 0; y < 5; y++) { - // Shortcuts - var laneIndex = x + 5 * y; - var lane = state[laneIndex]; - var TLane = T[laneIndex]; - var Tx1Lane = T[((x + 1) % 5) + 5 * y]; - var Tx2Lane = T[((x + 2) % 5) + 5 * y]; - - // Mix rows - lane.high = TLane.high ^ (~Tx1Lane.high & Tx2Lane.high); - lane.low = TLane.low ^ (~Tx1Lane.low & Tx2Lane.low); - } - } - - // Iota - var lane = state[0]; - var roundConstant = ROUND_CONSTANTS[round]; - lane.high ^= roundConstant.high; - lane.low ^= roundConstant.low;; - } - }, - - _doFinalize: function () { - // Shortcuts - var data = this._data; - var dataWords = data.words; - var nBitsTotal = this._nDataBytes * 8; - var nBitsLeft = data.sigBytes * 8; - var blockSizeBits = this.blockSize * 32; - - // Add padding - dataWords[nBitsLeft >>> 5] |= 0x1 << (24 - nBitsLeft % 32); - dataWords[((Math.ceil((nBitsLeft + 1) / blockSizeBits) * blockSizeBits) >>> 5) - 1] |= 0x80; - data.sigBytes = dataWords.length * 4; - - // Hash final blocks - this._process(); - - // Shortcuts - var state = this._state; - var outputLengthBytes = this.cfg.outputLength / 8; - var outputLengthLanes = outputLengthBytes / 8; - - // Squeeze - var hashWords = []; - for (var i = 0; i < outputLengthLanes; i++) { - // Shortcuts - var lane = state[i]; - var laneMsw = lane.high; - var laneLsw = lane.low; - - // Swap endian - laneMsw = ( - (((laneMsw << 8) | (laneMsw >>> 24)) & 0x00ff00ff) | - (((laneMsw << 24) | (laneMsw >>> 8)) & 0xff00ff00) - ); - laneLsw = ( - (((laneLsw << 8) | (laneLsw >>> 24)) & 0x00ff00ff) | - (((laneLsw << 24) | (laneLsw >>> 8)) & 0xff00ff00) - ); - - // Squeeze state to retrieve hash - hashWords.push(laneLsw); - hashWords.push(laneMsw); - } - - // Return final computed hash - return new WordArray.init(hashWords, outputLengthBytes); - }, - - clone: function () { - var clone = Hasher.clone.call(this); - - var state = clone._state = this._state.slice(0); - for (var i = 0; i < 25; i++) { - state[i] = state[i].clone(); - } - - return clone; - } - }); - - /** - * Shortcut function to the hasher's object interface. - * - * @param {WordArray|string} message The message to hash. - * - * @return {WordArray} The hash. - * - * @static - * - * @example - * - * var hash = CryptoJS.SHA3('message'); - * var hash = CryptoJS.SHA3(wordArray); - */ - C.SHA3 = Hasher._createHelper(SHA3); - - /** - * Shortcut function to the HMAC's object interface. - * - * @param {WordArray|string} message The message to hash. - * @param {WordArray|string} key The secret key. - * - * @return {WordArray} The HMAC. - * - * @static - * - * @example - * - * var hmac = CryptoJS.HmacSHA3(message, key); - */ - C.HmacSHA3 = Hasher._createHmacHelper(SHA3); - }(Math)); - - - return CryptoJS.SHA3; - -})); -},{"./core":32,"./x64-core":34}],34:[function(require,module,exports){ -;(function (root, factory) { - if (typeof exports === "object") { - // CommonJS - module.exports = exports = factory(require("./core")); - } - else if (typeof define === "function" && define.amd) { - // AMD - define(["./core"], factory); - } - else { - // Global (browser) - factory(root.CryptoJS); - } -}(this, function (CryptoJS) { - - (function (undefined) { - // Shortcuts - var C = CryptoJS; - var C_lib = C.lib; - var Base = C_lib.Base; - var X32WordArray = C_lib.WordArray; - - /** - * x64 namespace. - */ - var C_x64 = C.x64 = {}; - - /** - * A 64-bit word. - */ - var X64Word = C_x64.Word = Base.extend({ - /** - * Initializes a newly created 64-bit word. - * - * @param {number} high The high 32 bits. - * @param {number} low The low 32 bits. - * - * @example - * - * var x64Word = CryptoJS.x64.Word.create(0x00010203, 0x04050607); - */ - init: function (high, low) { - this.high = high; - this.low = low; - } - - /** - * Bitwise NOTs this word. - * - * @return {X64Word} A new x64-Word object after negating. - * - * @example - * - * var negated = x64Word.not(); - */ - // not: function () { - // var high = ~this.high; - // var low = ~this.low; - - // return X64Word.create(high, low); - // }, - - /** - * Bitwise ANDs this word with the passed word. - * - * @param {X64Word} word The x64-Word to AND with this word. - * - * @return {X64Word} A new x64-Word object after ANDing. - * - * @example - * - * var anded = x64Word.and(anotherX64Word); - */ - // and: function (word) { - // var high = this.high & word.high; - // var low = this.low & word.low; - - // return X64Word.create(high, low); - // }, - - /** - * Bitwise ORs this word with the passed word. - * - * @param {X64Word} word The x64-Word to OR with this word. - * - * @return {X64Word} A new x64-Word object after ORing. - * - * @example - * - * var ored = x64Word.or(anotherX64Word); - */ - // or: function (word) { - // var high = this.high | word.high; - // var low = this.low | word.low; - - // return X64Word.create(high, low); - // }, - - /** - * Bitwise XORs this word with the passed word. - * - * @param {X64Word} word The x64-Word to XOR with this word. - * - * @return {X64Word} A new x64-Word object after XORing. - * - * @example - * - * var xored = x64Word.xor(anotherX64Word); - */ - // xor: function (word) { - // var high = this.high ^ word.high; - // var low = this.low ^ word.low; - - // return X64Word.create(high, low); - // }, - - /** - * Shifts this word n bits to the left. - * - * @param {number} n The number of bits to shift. - * - * @return {X64Word} A new x64-Word object after shifting. - * - * @example - * - * var shifted = x64Word.shiftL(25); - */ - // shiftL: function (n) { - // if (n < 32) { - // var high = (this.high << n) | (this.low >>> (32 - n)); - // var low = this.low << n; - // } else { - // var high = this.low << (n - 32); - // var low = 0; - // } - - // return X64Word.create(high, low); - // }, - - /** - * Shifts this word n bits to the right. - * - * @param {number} n The number of bits to shift. - * - * @return {X64Word} A new x64-Word object after shifting. - * - * @example - * - * var shifted = x64Word.shiftR(7); - */ - // shiftR: function (n) { - // if (n < 32) { - // var low = (this.low >>> n) | (this.high << (32 - n)); - // var high = this.high >>> n; - // } else { - // var low = this.high >>> (n - 32); - // var high = 0; - // } - - // return X64Word.create(high, low); - // }, - - /** - * Rotates this word n bits to the left. - * - * @param {number} n The number of bits to rotate. - * - * @return {X64Word} A new x64-Word object after rotating. - * - * @example - * - * var rotated = x64Word.rotL(25); - */ - // rotL: function (n) { - // return this.shiftL(n).or(this.shiftR(64 - n)); - // }, - - /** - * Rotates this word n bits to the right. - * - * @param {number} n The number of bits to rotate. - * - * @return {X64Word} A new x64-Word object after rotating. - * - * @example - * - * var rotated = x64Word.rotR(7); - */ - // rotR: function (n) { - // return this.shiftR(n).or(this.shiftL(64 - n)); - // }, - - /** - * Adds this word with the passed word. - * - * @param {X64Word} word The x64-Word to add with this word. - * - * @return {X64Word} A new x64-Word object after adding. - * - * @example - * - * var added = x64Word.add(anotherX64Word); - */ - // add: function (word) { - // var low = (this.low + word.low) | 0; - // var carry = (low >>> 0) < (this.low >>> 0) ? 1 : 0; - // var high = (this.high + word.high + carry) | 0; - - // return X64Word.create(high, low); - // } - }); - - /** - * An array of 64-bit words. - * - * @property {Array} words The array of CryptoJS.x64.Word objects. - * @property {number} sigBytes The number of significant bytes in this word array. - */ - var X64WordArray = C_x64.WordArray = Base.extend({ - /** - * Initializes a newly created word array. - * - * @param {Array} words (Optional) An array of CryptoJS.x64.Word objects. - * @param {number} sigBytes (Optional) The number of significant bytes in the words. - * - * @example - * - * var wordArray = CryptoJS.x64.WordArray.create(); - * - * var wordArray = CryptoJS.x64.WordArray.create([ - * CryptoJS.x64.Word.create(0x00010203, 0x04050607), - * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f) - * ]); - * - * var wordArray = CryptoJS.x64.WordArray.create([ - * CryptoJS.x64.Word.create(0x00010203, 0x04050607), - * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f) - * ], 10); - */ - init: function (words, sigBytes) { - words = this.words = words || []; - - if (sigBytes != undefined) { - this.sigBytes = sigBytes; - } else { - this.sigBytes = words.length * 8; - } - }, - - /** - * Converts this 64-bit word array to a 32-bit word array. - * - * @return {CryptoJS.lib.WordArray} This word array's data as a 32-bit word array. - * - * @example - * - * var x32WordArray = x64WordArray.toX32(); - */ - toX32: function () { - // Shortcuts - var x64Words = this.words; - var x64WordsLength = x64Words.length; - - // Convert - var x32Words = []; - for (var i = 0; i < x64WordsLength; i++) { - var x64Word = x64Words[i]; - x32Words.push(x64Word.high); - x32Words.push(x64Word.low); - } - - return X32WordArray.create(x32Words, this.sigBytes); - }, - - /** - * Creates a copy of this word array. - * - * @return {X64WordArray} The clone. - * - * @example - * - * var clone = x64WordArray.clone(); - */ - clone: function () { - var clone = Base.clone.call(this); - - // Clone "words" array - var words = clone.words = this.words.slice(0); - - // Clone each X64Word object - var wordsLength = words.length; - for (var i = 0; i < wordsLength; i++) { - words[i] = words[i].clone(); - } - - return clone; - } - }); - }()); - - - return CryptoJS; - -})); -},{"./core":32}],"bignumber.js":[function(require,module,exports){ -'use strict'; - -module.exports = BigNumber; // jshint ignore:line - - -},{}],"web3":[function(require,module,exports){ -var web3 = require('./lib/web3'); -web3.providers.HttpProvider = require('./lib/web3/httpprovider'); -web3.providers.QtSyncProvider = require('./lib/web3/qtsync'); -web3.eth.contract = require('./lib/web3/contract'); -web3.eth.namereg = require('./lib/web3/namereg'); -web3.eth.sendIBANTransaction = require('./lib/web3/transfer'); - -// dont override global variable -if (typeof window !== 'undefined' && typeof window.web3 === 'undefined') { - window.web3 = web3; -} - -module.exports = web3; - - -},{"./lib/web3":9,"./lib/web3/contract":11,"./lib/web3/httpprovider":19,"./lib/web3/namereg":23,"./lib/web3/qtsync":26,"./lib/web3/transfer":29}]},{},["web3"]) -//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJsaWIvc29saWRpdHkvY29kZXIuanMiLCJsaWIvc29saWRpdHkvZm9ybWF0dGVycy5qcyIsImxpYi9zb2xpZGl0eS9wYXJhbS5qcyIsImxpYi91dGlscy9icm93c2VyLXhoci5qcyIsImxpYi91dGlscy9jb25maWcuanMiLCJsaWIvdXRpbHMvc2hhMy5qcyIsImxpYi91dGlscy91dGlscy5qcyIsImxpYi92ZXJzaW9uLmpzb24iLCJsaWIvd2ViMy5qcyIsImxpYi93ZWIzL2JhdGNoLmpzIiwibGliL3dlYjMvY29udHJhY3QuanMiLCJsaWIvd2ViMy9kYi5qcyIsImxpYi93ZWIzL2Vycm9ycy5qcyIsImxpYi93ZWIzL2V0aC5qcyIsImxpYi93ZWIzL2V2ZW50LmpzIiwibGliL3dlYjMvZmlsdGVyLmpzIiwibGliL3dlYjMvZm9ybWF0dGVycy5qcyIsImxpYi93ZWIzL2Z1bmN0aW9uLmpzIiwibGliL3dlYjMvaHR0cHByb3ZpZGVyLmpzIiwibGliL3dlYjMvaWNhcC5qcyIsImxpYi93ZWIzL2pzb25ycGMuanMiLCJsaWIvd2ViMy9tZXRob2QuanMiLCJsaWIvd2ViMy9uYW1lcmVnLmpzIiwibGliL3dlYjMvbmV0LmpzIiwibGliL3dlYjMvcHJvcGVydHkuanMiLCJsaWIvd2ViMy9xdHN5bmMuanMiLCJsaWIvd2ViMy9yZXF1ZXN0bWFuYWdlci5qcyIsImxpYi93ZWIzL3NoaC5qcyIsImxpYi93ZWIzL3RyYW5zZmVyLmpzIiwibGliL3dlYjMvd2F0Y2hlcy5qcyIsIm5vZGVfbW9kdWxlcy9icm93c2VyaWZ5L2xpYi9fZW1wdHkuanMiLCJub2RlX21vZHVsZXMvY3J5cHRvLWpzL2NvcmUuanMiLCJub2RlX21vZHVsZXMvY3J5cHRvLWpzL3NoYTMuanMiLCJub2RlX21vZHVsZXMvY3J5cHRvLWpzL3g2NC1jb3JlLmpzIiwibGliL3V0aWxzL2Jyb3dzZXItYm4uanMiLCJpbmRleC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMU5BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xmQTtBQUNBO0FBQ0E7QUFDQTs7QUNIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcExBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDblJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25NQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDak9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1S0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RQQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xIQTs7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNydUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbFVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9TQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBcbiAqIEBmaWxlIGNvZGVyLmpzXG4gKiBAYXV0aG9yIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbnZhciBCaWdOdW1iZXIgPSByZXF1aXJlKCdiaWdudW1iZXIuanMnKTtcbnZhciB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzL3V0aWxzJyk7XG52YXIgZiA9IHJlcXVpcmUoJy4vZm9ybWF0dGVycycpO1xudmFyIFNvbGlkaXR5UGFyYW0gPSByZXF1aXJlKCcuL3BhcmFtJyk7XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gY2hlY2sgaWYgYSB0eXBlIGlzIGFuIGFycmF5IHR5cGVcbiAqXG4gKiBAbWV0aG9kIGlzQXJyYXlUeXBlXG4gKiBAcGFyYW0ge1N0cmluZ30gdHlwZVxuICogQHJldHVybiB7Qm9vbH0gdHJ1ZSBpcyB0aGUgdHlwZSBpcyBhbiBhcnJheSwgb3RoZXJ3aXNlIGZhbHNlXG4gKi9cbnZhciBpc0FycmF5VHlwZSA9IGZ1bmN0aW9uICh0eXBlKSB7XG4gICAgcmV0dXJuIHR5cGUuc2xpY2UoLTIpID09PSAnW10nO1xufTtcblxuLyoqXG4gKiBTb2xpZGl0eVR5cGUgcHJvdG90eXBlIGlzIHVzZWQgdG8gZW5jb2RlL2RlY29kZSBzb2xpZGl0eSBwYXJhbXMgb2YgY2VydGFpbiB0eXBlXG4gKi9cbnZhciBTb2xpZGl0eVR5cGUgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdGhpcy5fbmFtZSA9IGNvbmZpZy5uYW1lO1xuICAgIHRoaXMuX21hdGNoID0gY29uZmlnLm1hdGNoO1xuICAgIHRoaXMuX21vZGUgPSBjb25maWcubW9kZTtcbiAgICB0aGlzLl9pbnB1dEZvcm1hdHRlciA9IGNvbmZpZy5pbnB1dEZvcm1hdHRlcjtcbiAgICB0aGlzLl9vdXRwdXRGb3JtYXR0ZXIgPSBjb25maWcub3V0cHV0Rm9ybWF0dGVyO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBkZXRlcm1pbmUgaWYgdGhpcyBTb2xpZGl0eVR5cGUgZG8gbWF0Y2ggZ2l2ZW4gdHlwZVxuICpcbiAqIEBtZXRob2QgaXNUeXBlXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZVxuICogQHJldHVybiB7Qm9vbH0gdHJ1ZSBpZiB0eXBlIG1hdGNoIHRoaXMgU29saWRpdHlUeXBlLCBvdGhlcndpc2UgZmFsc2VcbiAqL1xuU29saWRpdHlUeXBlLnByb3RvdHlwZS5pc1R5cGUgPSBmdW5jdGlvbiAobmFtZSkge1xuICAgIGlmICh0aGlzLl9tYXRjaCA9PT0gJ3N0cmljdCcpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX25hbWUgPT09IG5hbWUgfHwgKG5hbWUuaW5kZXhPZih0aGlzLl9uYW1lKSA9PT0gMCAmJiBuYW1lLnNsaWNlKHRoaXMuX25hbWUubGVuZ3RoKSA9PT0gJ1tdJyk7XG4gICAgfSBlbHNlIGlmICh0aGlzLl9tYXRjaCA9PT0gJ3ByZWZpeCcpIHtcbiAgICAgICAgLy8gVE9ETyBiZXR0ZXIgdHlwZSBkZXRlY3Rpb24hXG4gICAgICAgIHJldHVybiBuYW1lLmluZGV4T2YodGhpcy5fbmFtZSkgPT09IDA7XG4gICAgfVxufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byB0cmFuc2Zvcm0gcGxhaW4gcGFyYW0gdG8gU29saWRpdHlQYXJhbSBvYmplY3RcbiAqXG4gKiBAbWV0aG9kIGZvcm1hdElucHV0XG4gKiBAcGFyYW0ge09iamVjdH0gcGFyYW0gLSBwbGFpbiBvYmplY3QsIG9yIGFuIGFycmF5IG9mIG9iamVjdHNcbiAqIEBwYXJhbSB7Qm9vbH0gYXJyYXlUeXBlIC0gdHJ1ZSBpZiBhIHBhcmFtIHNob3VsZCBiZSBlbmNvZGVkIGFzIGFuIGFycmF5XG4gKiBAcmV0dXJuIHtTb2xpZGl0eVBhcmFtfSBlbmNvZGVkIHBhcmFtIHdyYXBwZWQgaW4gU29saWRpdHlQYXJhbSBvYmplY3QgXG4gKi9cblNvbGlkaXR5VHlwZS5wcm90b3R5cGUuZm9ybWF0SW5wdXQgPSBmdW5jdGlvbiAocGFyYW0sIGFycmF5VHlwZSkge1xuICAgIGlmICh1dGlscy5pc0FycmF5KHBhcmFtKSAmJiBhcnJheVR5cGUpIHsgLy8gVE9ETzogc2hvdWxkIGZhaWwgaWYgdGhpcyB0d28gYXJlIG5vdCB0aGUgc2FtZVxuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgIHJldHVybiBwYXJhbS5tYXAoZnVuY3Rpb24gKHApIHtcbiAgICAgICAgICAgIHJldHVybiBzZWxmLl9pbnB1dEZvcm1hdHRlcihwKTtcbiAgICAgICAgfSkucmVkdWNlKGZ1bmN0aW9uIChhY2MsIGN1cnJlbnQpIHtcbiAgICAgICAgICAgIHJldHVybiBhY2MuY29tYmluZShjdXJyZW50KTtcbiAgICAgICAgfSwgZi5mb3JtYXRJbnB1dEludChwYXJhbS5sZW5ndGgpKS53aXRoT2Zmc2V0KDMyKTtcbiAgICB9IFxuICAgIHJldHVybiB0aGlzLl9pbnB1dEZvcm1hdHRlcihwYXJhbSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIHRyYW5zb2Zvcm0gU29saWRpdHlQYXJhbSB0byBwbGFpbiBwYXJhbVxuICpcbiAqIEBtZXRob2QgZm9ybWF0T3V0cHV0XG4gKiBAcGFyYW0ge1NvbGlkaXR5UGFyYW19IGJ5dGVBcnJheVxuICogQHBhcmFtIHtCb29sfSBhcnJheVR5cGUgLSB0cnVlIGlmIGEgcGFyYW0gc2hvdWxkIGJlIGRlY29kZWQgYXMgYW4gYXJyYXlcbiAqIEByZXR1cm4ge09iamVjdH0gcGxhaW4gZGVjb2RlZCBwYXJhbVxuICovXG5Tb2xpZGl0eVR5cGUucHJvdG90eXBlLmZvcm1hdE91dHB1dCA9IGZ1bmN0aW9uIChwYXJhbSwgYXJyYXlUeXBlKSB7XG4gICAgaWYgKGFycmF5VHlwZSkge1xuICAgICAgICAvLyBsZXQncyBhc3N1bWUsIHRoYXQgd2Ugc29saWRpdHkgd2lsbCBuZXZlciByZXR1cm4gbG9uZyBhcnJheXMgOlAgXG4gICAgICAgIHZhciByZXN1bHQgPSBbXTtcbiAgICAgICAgdmFyIGxlbmd0aCA9IG5ldyBCaWdOdW1iZXIocGFyYW0uZHluYW1pY1BhcnQoKS5zbGljZSgwLCA2NCksIDE2KTtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGggKiA2NDsgaSArPSA2NCkge1xuICAgICAgICAgICAgcmVzdWx0LnB1c2godGhpcy5fb3V0cHV0Rm9ybWF0dGVyKG5ldyBTb2xpZGl0eVBhcmFtKHBhcmFtLmR5bmFtaWNQYXJ0KCkuc3Vic3RyKGkgKyA2NCwgNjQpKSkpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLl9vdXRwdXRGb3JtYXR0ZXIocGFyYW0pO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBzbGljZSBzaW5nbGUgcGFyYW0gZnJvbSBieXRlc1xuICpcbiAqIEBtZXRob2Qgc2xpY2VQYXJhbVxuICogQHBhcmFtIHtTdHJpbmd9IGJ5dGVzXG4gKiBAcGFyYW0ge051bWJlcn0gaW5kZXggb2YgcGFyYW0gdG8gc2xpY2VcbiAqIEBwYXJhbSB7U3RyaW5nfSB0eXBlXG4gKiBAcmV0dXJucyB7U29saWRpdHlQYXJhbX0gcGFyYW1cbiAqL1xuU29saWRpdHlUeXBlLnByb3RvdHlwZS5zbGljZVBhcmFtID0gZnVuY3Rpb24gKGJ5dGVzLCBpbmRleCwgdHlwZSkge1xuICAgIGlmICh0aGlzLl9tb2RlID09PSAnYnl0ZXMnKSB7XG4gICAgICAgIHJldHVybiBTb2xpZGl0eVBhcmFtLmRlY29kZUJ5dGVzKGJ5dGVzLCBpbmRleCk7XG4gICAgfSBlbHNlIGlmIChpc0FycmF5VHlwZSh0eXBlKSkge1xuICAgICAgICByZXR1cm4gU29saWRpdHlQYXJhbS5kZWNvZGVBcnJheShieXRlcywgaW5kZXgpO1xuICAgIH1cbiAgICByZXR1cm4gU29saWRpdHlQYXJhbS5kZWNvZGVQYXJhbShieXRlcywgaW5kZXgpO1xufTtcblxuLyoqXG4gKiBTb2xpZGl0eUNvZGVyIHByb3RvdHlwZSBzaG91bGQgYmUgdXNlZCB0byBlbmNvZGUvZGVjb2RlIHNvbGlkaXR5IHBhcmFtcyBvZiBhbnkgdHlwZVxuICovXG52YXIgU29saWRpdHlDb2RlciA9IGZ1bmN0aW9uICh0eXBlcykge1xuICAgIHRoaXMuX3R5cGVzID0gdHlwZXM7XG59O1xuXG4vKipcbiAqIFRoaXMgbWV0aG9kIHNob3VsZCBiZSB1c2VkIHRvIHRyYW5zZm9ybSB0eXBlIHRvIFNvbGlkaXR5VHlwZVxuICpcbiAqIEBtZXRob2QgX3JlcXVpcmVUeXBlXG4gKiBAcGFyYW0ge1N0cmluZ30gdHlwZVxuICogQHJldHVybnMge1NvbGlkaXR5VHlwZX0gXG4gKiBAdGhyb3dzIHtFcnJvcn0gdGhyb3dzIGlmIG5vIG1hdGNoaW5nIHR5cGUgaXMgZm91bmRcbiAqL1xuU29saWRpdHlDb2Rlci5wcm90b3R5cGUuX3JlcXVpcmVUeXBlID0gZnVuY3Rpb24gKHR5cGUpIHtcbiAgICB2YXIgc29saWRpdHlUeXBlID0gdGhpcy5fdHlwZXMuZmlsdGVyKGZ1bmN0aW9uICh0KSB7XG4gICAgICAgIHJldHVybiB0LmlzVHlwZSh0eXBlKTtcbiAgICB9KVswXTtcblxuICAgIGlmICghc29saWRpdHlUeXBlKSB7XG4gICAgICAgIHRocm93IEVycm9yKCdpbnZhbGlkIHNvbGlkaXR5IHR5cGUhOiAnICsgdHlwZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNvbGlkaXR5VHlwZTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gdHJhbnNmb3JtIHBsYWluIHBhcmFtIG9mIGdpdmVuIHR5cGUgdG8gU29saWRpdHlQYXJhbVxuICpcbiAqIEBtZXRob2QgX2Zvcm1hdElucHV0XG4gKiBAcGFyYW0ge1N0cmluZ30gdHlwZSBvZiBwYXJhbVxuICogQHBhcmFtIHtPYmplY3R9IHBsYWluIHBhcmFtXG4gKiBAcmV0dXJuIHtTb2xpZGl0eVBhcmFtfVxuICovXG5Tb2xpZGl0eUNvZGVyLnByb3RvdHlwZS5fZm9ybWF0SW5wdXQgPSBmdW5jdGlvbiAodHlwZSwgcGFyYW0pIHtcbiAgICByZXR1cm4gdGhpcy5fcmVxdWlyZVR5cGUodHlwZSkuZm9ybWF0SW5wdXQocGFyYW0sIGlzQXJyYXlUeXBlKHR5cGUpKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZW5jb2RlIHBsYWluIHBhcmFtXG4gKlxuICogQG1ldGhvZCBlbmNvZGVQYXJhbVxuICogQHBhcmFtIHtTdHJpbmd9IHR5cGVcbiAqIEBwYXJhbSB7T2JqZWN0fSBwbGFpbiBwYXJhbVxuICogQHJldHVybiB7U3RyaW5nfSBlbmNvZGVkIHBsYWluIHBhcmFtXG4gKi9cblNvbGlkaXR5Q29kZXIucHJvdG90eXBlLmVuY29kZVBhcmFtID0gZnVuY3Rpb24gKHR5cGUsIHBhcmFtKSB7XG4gICAgcmV0dXJuIHRoaXMuX2Zvcm1hdElucHV0KHR5cGUsIHBhcmFtKS5lbmNvZGUoKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZW5jb2RlIGxpc3Qgb2YgcGFyYW1zXG4gKlxuICogQG1ldGhvZCBlbmNvZGVQYXJhbXNcbiAqIEBwYXJhbSB7QXJyYXl9IHR5cGVzXG4gKiBAcGFyYW0ge0FycmF5fSBwYXJhbXNcbiAqIEByZXR1cm4ge1N0cmluZ30gZW5jb2RlZCBsaXN0IG9mIHBhcmFtc1xuICovXG5Tb2xpZGl0eUNvZGVyLnByb3RvdHlwZS5lbmNvZGVQYXJhbXMgPSBmdW5jdGlvbiAodHlwZXMsIHBhcmFtcykge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgc29saWRpdHlQYXJhbXMgPSB0eXBlcy5tYXAoZnVuY3Rpb24gKHR5cGUsIGluZGV4KSB7XG4gICAgICAgIHJldHVybiBzZWxmLl9mb3JtYXRJbnB1dCh0eXBlLCBwYXJhbXNbaW5kZXhdKTtcbiAgICB9KTtcblxuICAgIHJldHVybiBTb2xpZGl0eVBhcmFtLmVuY29kZUxpc3Qoc29saWRpdHlQYXJhbXMpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBkZWNvZGUgYnl0ZXMgdG8gcGxhaW4gcGFyYW1cbiAqXG4gKiBAbWV0aG9kIGRlY29kZVBhcmFtXG4gKiBAcGFyYW0ge1N0cmluZ30gdHlwZVxuICogQHBhcmFtIHtTdHJpbmd9IGJ5dGVzXG4gKiBAcmV0dXJuIHtPYmplY3R9IHBsYWluIHBhcmFtXG4gKi9cblNvbGlkaXR5Q29kZXIucHJvdG90eXBlLmRlY29kZVBhcmFtID0gZnVuY3Rpb24gKHR5cGUsIGJ5dGVzKSB7XG4gICAgcmV0dXJuIHRoaXMuZGVjb2RlUGFyYW1zKFt0eXBlXSwgYnl0ZXMpWzBdO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBkZWNvZGUgbGlzdCBvZiBwYXJhbXNcbiAqXG4gKiBAbWV0aG9kIGRlY29kZVBhcmFtXG4gKiBAcGFyYW0ge0FycmF5fSB0eXBlc1xuICogQHBhcmFtIHtTdHJpbmd9IGJ5dGVzXG4gKiBAcmV0dXJuIHtBcnJheX0gYXJyYXkgb2YgcGxhaW4gcGFyYW1zXG4gKi9cblNvbGlkaXR5Q29kZXIucHJvdG90eXBlLmRlY29kZVBhcmFtcyA9IGZ1bmN0aW9uICh0eXBlcywgYnl0ZXMpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgcmV0dXJuIHR5cGVzLm1hcChmdW5jdGlvbiAodHlwZSwgaW5kZXgpIHtcbiAgICAgICAgdmFyIHNvbGlkaXR5VHlwZSA9IHNlbGYuX3JlcXVpcmVUeXBlKHR5cGUpO1xuICAgICAgICB2YXIgcCA9IHNvbGlkaXR5VHlwZS5zbGljZVBhcmFtKGJ5dGVzLCBpbmRleCwgdHlwZSk7XG4gICAgICAgIHJldHVybiBzb2xpZGl0eVR5cGUuZm9ybWF0T3V0cHV0KHAsIGlzQXJyYXlUeXBlKHR5cGUpKTtcbiAgICB9KTtcbn07XG5cbnZhciBjb2RlciA9IG5ldyBTb2xpZGl0eUNvZGVyKFtcbiAgICBuZXcgU29saWRpdHlUeXBlKHtcbiAgICAgICAgbmFtZTogJ2FkZHJlc3MnLFxuICAgICAgICBtYXRjaDogJ3N0cmljdCcsXG4gICAgICAgIG1vZGU6ICd2YWx1ZScsXG4gICAgICAgIGlucHV0Rm9ybWF0dGVyOiBmLmZvcm1hdElucHV0SW50LFxuICAgICAgICBvdXRwdXRGb3JtYXR0ZXI6IGYuZm9ybWF0T3V0cHV0QWRkcmVzc1xuICAgIH0pLFxuICAgIG5ldyBTb2xpZGl0eVR5cGUoe1xuICAgICAgICBuYW1lOiAnYm9vbCcsXG4gICAgICAgIG1hdGNoOiAnc3RyaWN0JyxcbiAgICAgICAgbW9kZTogJ3ZhbHVlJyxcbiAgICAgICAgaW5wdXRGb3JtYXR0ZXI6IGYuZm9ybWF0SW5wdXRCb29sLFxuICAgICAgICBvdXRwdXRGb3JtYXR0ZXI6IGYuZm9ybWF0T3V0cHV0Qm9vbFxuICAgIH0pLFxuICAgIG5ldyBTb2xpZGl0eVR5cGUoe1xuICAgICAgICBuYW1lOiAnaW50JyxcbiAgICAgICAgbWF0Y2g6ICdwcmVmaXgnLFxuICAgICAgICBtb2RlOiAndmFsdWUnLFxuICAgICAgICBpbnB1dEZvcm1hdHRlcjogZi5mb3JtYXRJbnB1dEludCxcbiAgICAgICAgb3V0cHV0Rm9ybWF0dGVyOiBmLmZvcm1hdE91dHB1dEludCxcbiAgICB9KSxcbiAgICBuZXcgU29saWRpdHlUeXBlKHtcbiAgICAgICAgbmFtZTogJ3VpbnQnLFxuICAgICAgICBtYXRjaDogJ3ByZWZpeCcsXG4gICAgICAgIG1vZGU6ICd2YWx1ZScsXG4gICAgICAgIGlucHV0Rm9ybWF0dGVyOiBmLmZvcm1hdElucHV0SW50LFxuICAgICAgICBvdXRwdXRGb3JtYXR0ZXI6IGYuZm9ybWF0T3V0cHV0VUludFxuICAgIH0pLFxuICAgIG5ldyBTb2xpZGl0eVR5cGUoe1xuICAgICAgICBuYW1lOiAnYnl0ZXMnLFxuICAgICAgICBtYXRjaDogJ3N0cmljdCcsXG4gICAgICAgIG1vZGU6ICdieXRlcycsXG4gICAgICAgIGlucHV0Rm9ybWF0dGVyOiBmLmZvcm1hdElucHV0RHluYW1pY0J5dGVzLFxuICAgICAgICBvdXRwdXRGb3JtYXR0ZXI6IGYuZm9ybWF0T3V0cHV0RHluYW1pY0J5dGVzXG4gICAgfSksXG4gICAgbmV3IFNvbGlkaXR5VHlwZSh7XG4gICAgICAgIG5hbWU6ICdieXRlcycsXG4gICAgICAgIG1hdGNoOiAncHJlZml4JyxcbiAgICAgICAgbW9kZTogJ3ZhbHVlJyxcbiAgICAgICAgaW5wdXRGb3JtYXR0ZXI6IGYuZm9ybWF0SW5wdXRCeXRlcyxcbiAgICAgICAgb3V0cHV0Rm9ybWF0dGVyOiBmLmZvcm1hdE91dHB1dEJ5dGVzXG4gICAgfSksXG4gICAgbmV3IFNvbGlkaXR5VHlwZSh7XG4gICAgICAgIG5hbWU6ICdyZWFsJyxcbiAgICAgICAgbWF0Y2g6ICdwcmVmaXgnLFxuICAgICAgICBtb2RlOiAndmFsdWUnLFxuICAgICAgICBpbnB1dEZvcm1hdHRlcjogZi5mb3JtYXRJbnB1dFJlYWwsXG4gICAgICAgIG91dHB1dEZvcm1hdHRlcjogZi5mb3JtYXRPdXRwdXRSZWFsXG4gICAgfSksXG4gICAgbmV3IFNvbGlkaXR5VHlwZSh7XG4gICAgICAgIG5hbWU6ICd1cmVhbCcsXG4gICAgICAgIG1hdGNoOiAncHJlZml4JyxcbiAgICAgICAgbW9kZTogJ3ZhbHVlJyxcbiAgICAgICAgaW5wdXRGb3JtYXR0ZXI6IGYuZm9ybWF0SW5wdXRSZWFsLFxuICAgICAgICBvdXRwdXRGb3JtYXR0ZXI6IGYuZm9ybWF0T3V0cHV0VVJlYWxcbiAgICB9KVxuXSk7XG5cbm1vZHVsZS5leHBvcnRzID0gY29kZXI7XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqIFxuICogQGZpbGUgZm9ybWF0dGVycy5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgQmlnTnVtYmVyID0gcmVxdWlyZSgnYmlnbnVtYmVyLmpzJyk7XG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy91dGlscycpO1xudmFyIGMgPSByZXF1aXJlKCcuLi91dGlscy9jb25maWcnKTtcbnZhciBTb2xpZGl0eVBhcmFtID0gcmVxdWlyZSgnLi9wYXJhbScpO1xuXG5cbi8qKlxuICogRm9ybWF0cyBpbnB1dCB2YWx1ZSB0byBieXRlIHJlcHJlc2VudGF0aW9uIG9mIGludFxuICogSWYgdmFsdWUgaXMgbmVnYXRpdmUsIHJldHVybiBpdCdzIHR3bydzIGNvbXBsZW1lbnRcbiAqIElmIHRoZSB2YWx1ZSBpcyBmbG9hdGluZyBwb2ludCwgcm91bmQgaXQgZG93blxuICpcbiAqIEBtZXRob2QgZm9ybWF0SW5wdXRJbnRcbiAqIEBwYXJhbSB7U3RyaW5nfE51bWJlcnxCaWdOdW1iZXJ9IHZhbHVlIHRoYXQgbmVlZHMgdG8gYmUgZm9ybWF0dGVkXG4gKiBAcmV0dXJucyB7U29saWRpdHlQYXJhbX1cbiAqL1xudmFyIGZvcm1hdElucHV0SW50ID0gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgdmFyIHBhZGRpbmcgPSBjLkVUSF9QQURESU5HICogMjtcbiAgICBCaWdOdW1iZXIuY29uZmlnKGMuRVRIX0JJR05VTUJFUl9ST1VORElOR19NT0RFKTtcbiAgICB2YXIgcmVzdWx0ID0gdXRpbHMucGFkTGVmdCh1dGlscy50b1R3b3NDb21wbGVtZW50KHZhbHVlKS5yb3VuZCgpLnRvU3RyaW5nKDE2KSwgcGFkZGluZyk7XG4gICAgcmV0dXJuIG5ldyBTb2xpZGl0eVBhcmFtKHJlc3VsdCk7XG59O1xuXG4vKipcbiAqIEZvcm1hdHMgaW5wdXQgdmFsdWUgdG8gYnl0ZSByZXByZXNlbnRhdGlvbiBvZiBzdHJpbmdcbiAqXG4gKiBAbWV0aG9kIGZvcm1hdElucHV0Qnl0ZXNcbiAqIEBwYXJhbSB7U3RyaW5nfVxuICogQHJldHVybnMge1NvbGlkaXR5UGFyYW19XG4gKi9cbnZhciBmb3JtYXRJbnB1dEJ5dGVzID0gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgdmFyIHJlc3VsdCA9IHV0aWxzLmZyb21Bc2NpaSh2YWx1ZSwgYy5FVEhfUEFERElORykuc3Vic3RyKDIpO1xuICAgIHJldHVybiBuZXcgU29saWRpdHlQYXJhbShyZXN1bHQpO1xufTtcblxuLyoqXG4gKiBGb3JtYXRzIGlucHV0IHZhbHVlIHRvIGJ5dGUgcmVwcmVzZW50YXRpb24gb2Ygc3RyaW5nXG4gKlxuICogQG1ldGhvZCBmb3JtYXRJbnB1dER5bmFtaWNCeXRlc1xuICogQHBhcmFtIHtTdHJpbmd9XG4gKiBAcmV0dXJucyB7U29saWRpdHlQYXJhbX1cbiAqL1xudmFyIGZvcm1hdElucHV0RHluYW1pY0J5dGVzID0gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgdmFyIHJlc3VsdCA9IHV0aWxzLmZyb21Bc2NpaSh2YWx1ZSwgYy5FVEhfUEFERElORykuc3Vic3RyKDIpO1xuICAgIHJldHVybiBuZXcgU29saWRpdHlQYXJhbShmb3JtYXRJbnB1dEludCh2YWx1ZS5sZW5ndGgpLnZhbHVlICsgcmVzdWx0LCAzMik7XG59O1xuXG4vKipcbiAqIEZvcm1hdHMgaW5wdXQgdmFsdWUgdG8gYnl0ZSByZXByZXNlbnRhdGlvbiBvZiBib29sXG4gKlxuICogQG1ldGhvZCBmb3JtYXRJbnB1dEJvb2xcbiAqIEBwYXJhbSB7Qm9vbGVhbn1cbiAqIEByZXR1cm5zIHtTb2xpZGl0eVBhcmFtfVxuICovXG52YXIgZm9ybWF0SW5wdXRCb29sID0gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgdmFyIHJlc3VsdCA9ICcwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAnICsgKHZhbHVlID8gICcxJyA6ICcwJyk7XG4gICAgcmV0dXJuIG5ldyBTb2xpZGl0eVBhcmFtKHJlc3VsdCk7XG59O1xuXG4vKipcbiAqIEZvcm1hdHMgaW5wdXQgdmFsdWUgdG8gYnl0ZSByZXByZXNlbnRhdGlvbiBvZiByZWFsXG4gKiBWYWx1ZXMgYXJlIG11bHRpcGxpZWQgYnkgMl5tIGFuZCBlbmNvZGVkIGFzIGludGVnZXJzXG4gKlxuICogQG1ldGhvZCBmb3JtYXRJbnB1dFJlYWxcbiAqIEBwYXJhbSB7U3RyaW5nfE51bWJlcnxCaWdOdW1iZXJ9XG4gKiBAcmV0dXJucyB7U29saWRpdHlQYXJhbX1cbiAqL1xudmFyIGZvcm1hdElucHV0UmVhbCA9IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgIHJldHVybiBmb3JtYXRJbnB1dEludChuZXcgQmlnTnVtYmVyKHZhbHVlKS50aW1lcyhuZXcgQmlnTnVtYmVyKDIpLnBvdygxMjgpKSk7XG59O1xuXG4vKipcbiAqIENoZWNrIGlmIGlucHV0IHZhbHVlIGlzIG5lZ2F0aXZlXG4gKlxuICogQG1ldGhvZCBzaWduZWRJc05lZ2F0aXZlXG4gKiBAcGFyYW0ge1N0cmluZ30gdmFsdWUgaXMgaGV4IGZvcm1hdFxuICogQHJldHVybnMge0Jvb2xlYW59IHRydWUgaWYgaXQgaXMgbmVnYXRpdmUsIG90aGVyd2lzZSBmYWxzZVxuICovXG52YXIgc2lnbmVkSXNOZWdhdGl2ZSA9IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgIHJldHVybiAobmV3IEJpZ051bWJlcih2YWx1ZS5zdWJzdHIoMCwgMSksIDE2KS50b1N0cmluZygyKS5zdWJzdHIoMCwgMSkpID09PSAnMSc7XG59O1xuXG4vKipcbiAqIEZvcm1hdHMgcmlnaHQtYWxpZ25lZCBvdXRwdXQgYnl0ZXMgdG8gaW50XG4gKlxuICogQG1ldGhvZCBmb3JtYXRPdXRwdXRJbnRcbiAqIEBwYXJhbSB7U29saWRpdHlQYXJhbX0gcGFyYW1cbiAqIEByZXR1cm5zIHtCaWdOdW1iZXJ9IHJpZ2h0LWFsaWduZWQgb3V0cHV0IGJ5dGVzIGZvcm1hdHRlZCB0byBiaWcgbnVtYmVyXG4gKi9cbnZhciBmb3JtYXRPdXRwdXRJbnQgPSBmdW5jdGlvbiAocGFyYW0pIHtcbiAgICB2YXIgdmFsdWUgPSBwYXJhbS5zdGF0aWNQYXJ0KCkgfHwgXCIwXCI7XG5cbiAgICAvLyBjaGVjayBpZiBpdCdzIG5lZ2F0aXZlIG51bWJlclxuICAgIC8vIGl0IGl0IGlzLCByZXR1cm4gdHdvJ3MgY29tcGxlbWVudFxuICAgIGlmIChzaWduZWRJc05lZ2F0aXZlKHZhbHVlKSkge1xuICAgICAgICByZXR1cm4gbmV3IEJpZ051bWJlcih2YWx1ZSwgMTYpLm1pbnVzKG5ldyBCaWdOdW1iZXIoJ2ZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmYnLCAxNikpLm1pbnVzKDEpO1xuICAgIH1cbiAgICByZXR1cm4gbmV3IEJpZ051bWJlcih2YWx1ZSwgMTYpO1xufTtcblxuLyoqXG4gKiBGb3JtYXRzIHJpZ2h0LWFsaWduZWQgb3V0cHV0IGJ5dGVzIHRvIHVpbnRcbiAqXG4gKiBAbWV0aG9kIGZvcm1hdE91dHB1dFVJbnRcbiAqIEBwYXJhbSB7U29saWRpdHlQYXJhbX1cbiAqIEByZXR1cm5zIHtCaWdOdW1lYmVyfSByaWdodC1hbGlnbmVkIG91dHB1dCBieXRlcyBmb3JtYXR0ZWQgdG8gdWludFxuICovXG52YXIgZm9ybWF0T3V0cHV0VUludCA9IGZ1bmN0aW9uIChwYXJhbSkge1xuICAgIHZhciB2YWx1ZSA9IHBhcmFtLnN0YXRpY1BhcnQoKSB8fCBcIjBcIjtcbiAgICByZXR1cm4gbmV3IEJpZ051bWJlcih2YWx1ZSwgMTYpO1xufTtcblxuLyoqXG4gKiBGb3JtYXRzIHJpZ2h0LWFsaWduZWQgb3V0cHV0IGJ5dGVzIHRvIHJlYWxcbiAqXG4gKiBAbWV0aG9kIGZvcm1hdE91dHB1dFJlYWxcbiAqIEBwYXJhbSB7U29saWRpdHlQYXJhbX1cbiAqIEByZXR1cm5zIHtCaWdOdW1iZXJ9IGlucHV0IGJ5dGVzIGZvcm1hdHRlZCB0byByZWFsXG4gKi9cbnZhciBmb3JtYXRPdXRwdXRSZWFsID0gZnVuY3Rpb24gKHBhcmFtKSB7XG4gICAgcmV0dXJuIGZvcm1hdE91dHB1dEludChwYXJhbSkuZGl2aWRlZEJ5KG5ldyBCaWdOdW1iZXIoMikucG93KDEyOCkpOyBcbn07XG5cbi8qKlxuICogRm9ybWF0cyByaWdodC1hbGlnbmVkIG91dHB1dCBieXRlcyB0byB1cmVhbFxuICpcbiAqIEBtZXRob2QgZm9ybWF0T3V0cHV0VVJlYWxcbiAqIEBwYXJhbSB7U29saWRpdHlQYXJhbX1cbiAqIEByZXR1cm5zIHtCaWdOdW1iZXJ9IGlucHV0IGJ5dGVzIGZvcm1hdHRlZCB0byB1cmVhbFxuICovXG52YXIgZm9ybWF0T3V0cHV0VVJlYWwgPSBmdW5jdGlvbiAocGFyYW0pIHtcbiAgICByZXR1cm4gZm9ybWF0T3V0cHV0VUludChwYXJhbSkuZGl2aWRlZEJ5KG5ldyBCaWdOdW1iZXIoMikucG93KDEyOCkpOyBcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZm9ybWF0IG91dHB1dCBib29sXG4gKlxuICogQG1ldGhvZCBmb3JtYXRPdXRwdXRCb29sXG4gKiBAcGFyYW0ge1NvbGlkaXR5UGFyYW19XG4gKiBAcmV0dXJucyB7Qm9vbGVhbn0gcmlnaHQtYWxpZ25lZCBpbnB1dCBieXRlcyBmb3JtYXR0ZWQgdG8gYm9vbFxuICovXG52YXIgZm9ybWF0T3V0cHV0Qm9vbCA9IGZ1bmN0aW9uIChwYXJhbSkge1xuICAgIHJldHVybiBwYXJhbS5zdGF0aWNQYXJ0KCkgPT09ICcwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAxJyA/IHRydWUgOiBmYWxzZTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZm9ybWF0IG91dHB1dCBzdHJpbmdcbiAqXG4gKiBAbWV0aG9kIGZvcm1hdE91dHB1dEJ5dGVzXG4gKiBAcGFyYW0ge1NvbGlkaXR5UGFyYW19IGxlZnQtYWxpZ25lZCBoZXggcmVwcmVzZW50YXRpb24gb2Ygc3RyaW5nXG4gKiBAcmV0dXJucyB7U3RyaW5nfSBhc2NpaSBzdHJpbmdcbiAqL1xudmFyIGZvcm1hdE91dHB1dEJ5dGVzID0gZnVuY3Rpb24gKHBhcmFtKSB7XG4gICAgLy8gbGVuZ3RoIG1pZ2h0IGFsc28gYmUgaW1wb3J0YW50IVxuICAgIHJldHVybiB1dGlscy50b0FzY2lpKHBhcmFtLnN0YXRpY1BhcnQoKSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGZvcm1hdCBvdXRwdXQgc3RyaW5nXG4gKlxuICogQG1ldGhvZCBmb3JtYXRPdXRwdXREeW5hbWljQnl0ZXNcbiAqIEBwYXJhbSB7U29saWRpdHlQYXJhbX0gbGVmdC1hbGlnbmVkIGhleCByZXByZXNlbnRhdGlvbiBvZiBzdHJpbmdcbiAqIEByZXR1cm5zIHtTdHJpbmd9IGFzY2lpIHN0cmluZ1xuICovXG52YXIgZm9ybWF0T3V0cHV0RHluYW1pY0J5dGVzID0gZnVuY3Rpb24gKHBhcmFtKSB7XG4gICAgLy8gbGVuZ3RoIG1pZ2h0IGFsc28gYmUgaW1wb3J0YW50IVxuICAgIHJldHVybiB1dGlscy50b0FzY2lpKHBhcmFtLmR5bmFtaWNQYXJ0KCkuc2xpY2UoNjQpKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZm9ybWF0IG91dHB1dCBhZGRyZXNzXG4gKlxuICogQG1ldGhvZCBmb3JtYXRPdXRwdXRBZGRyZXNzXG4gKiBAcGFyYW0ge1NvbGlkaXR5UGFyYW19IHJpZ2h0LWFsaWduZWQgaW5wdXQgYnl0ZXNcbiAqIEByZXR1cm5zIHtTdHJpbmd9IGFkZHJlc3NcbiAqL1xudmFyIGZvcm1hdE91dHB1dEFkZHJlc3MgPSBmdW5jdGlvbiAocGFyYW0pIHtcbiAgICB2YXIgdmFsdWUgPSBwYXJhbS5zdGF0aWNQYXJ0KCk7XG4gICAgcmV0dXJuIFwiMHhcIiArIHZhbHVlLnNsaWNlKHZhbHVlLmxlbmd0aCAtIDQwLCB2YWx1ZS5sZW5ndGgpO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgZm9ybWF0SW5wdXRJbnQ6IGZvcm1hdElucHV0SW50LFxuICAgIGZvcm1hdElucHV0Qnl0ZXM6IGZvcm1hdElucHV0Qnl0ZXMsXG4gICAgZm9ybWF0SW5wdXREeW5hbWljQnl0ZXM6IGZvcm1hdElucHV0RHluYW1pY0J5dGVzLFxuICAgIGZvcm1hdElucHV0Qm9vbDogZm9ybWF0SW5wdXRCb29sLFxuICAgIGZvcm1hdElucHV0UmVhbDogZm9ybWF0SW5wdXRSZWFsLFxuICAgIGZvcm1hdE91dHB1dEludDogZm9ybWF0T3V0cHV0SW50LFxuICAgIGZvcm1hdE91dHB1dFVJbnQ6IGZvcm1hdE91dHB1dFVJbnQsXG4gICAgZm9ybWF0T3V0cHV0UmVhbDogZm9ybWF0T3V0cHV0UmVhbCxcbiAgICBmb3JtYXRPdXRwdXRVUmVhbDogZm9ybWF0T3V0cHV0VVJlYWwsXG4gICAgZm9ybWF0T3V0cHV0Qm9vbDogZm9ybWF0T3V0cHV0Qm9vbCxcbiAgICBmb3JtYXRPdXRwdXRCeXRlczogZm9ybWF0T3V0cHV0Qnl0ZXMsXG4gICAgZm9ybWF0T3V0cHV0RHluYW1pY0J5dGVzOiBmb3JtYXRPdXRwdXREeW5hbWljQnl0ZXMsXG4gICAgZm9ybWF0T3V0cHV0QWRkcmVzczogZm9ybWF0T3V0cHV0QWRkcmVzc1xufTtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogXG4gKiBAZmlsZSBwYXJhbS5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy91dGlscycpO1xuXG4vKipcbiAqIFNvbGlkaXR5UGFyYW0gb2JqZWN0IHByb3RvdHlwZS5cbiAqIFNob3VsZCBiZSB1c2VkIHdoZW4gZW5jb2RpbmcsIGRlY29kaW5nIHNvbGlkaXR5IGJ5dGVzXG4gKi9cbnZhciBTb2xpZGl0eVBhcmFtID0gZnVuY3Rpb24gKHZhbHVlLCBvZmZzZXQpIHtcbiAgICB0aGlzLnZhbHVlID0gdmFsdWUgfHwgJyc7XG4gICAgdGhpcy5vZmZzZXQgPSBvZmZzZXQ7IC8vIG9mZnNldCBpbiBieXRlc1xufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgdXNlZCB0byBnZXQgbGVuZ3RoIG9mIHBhcmFtcydzIGR5bmFtaWMgcGFydFxuICogXG4gKiBAbWV0aG9kIGR5bmFtaWNQYXJ0TGVuZ3RoXG4gKiBAcmV0dXJucyB7TnVtYmVyfSBsZW5ndGggb2YgZHluYW1pYyBwYXJ0IChpbiBieXRlcylcbiAqL1xuU29saWRpdHlQYXJhbS5wcm90b3R5cGUuZHluYW1pY1BhcnRMZW5ndGggPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuZHluYW1pY1BhcnQoKS5sZW5ndGggLyAyO1xufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgdXNlZCB0byBjcmVhdGUgY29weSBvZiBzb2xpZGl0eSBwYXJhbSB3aXRoIGRpZmZlcmVudCBvZmZzZXRcbiAqXG4gKiBAbWV0aG9kIHdpdGhPZmZzZXRcbiAqIEBwYXJhbSB7TnVtYmVyfSBvZmZzZXQgbGVuZ3RoIGluIGJ5dGVzXG4gKiBAcmV0dXJucyB7U29saWRpdHlQYXJhbX0gbmV3IHNvbGlkaXR5IHBhcmFtIHdpdGggYXBwbGllZCBvZmZzZXRcbiAqL1xuU29saWRpdHlQYXJhbS5wcm90b3R5cGUud2l0aE9mZnNldCA9IGZ1bmN0aW9uIChvZmZzZXQpIHtcbiAgICByZXR1cm4gbmV3IFNvbGlkaXR5UGFyYW0odGhpcy52YWx1ZSwgb2Zmc2V0KTtcbn07XG5cbi8qKlxuICogVGhpcyBtZXRob2Qgc2hvdWxkIGJlIHVzZWQgdG8gY29tYmluZSBzb2xpZGl0eSBwYXJhbXMgdG9nZXRoZXJcbiAqIGVnLiB3aGVuIGFwcGVuZGluZyBhbiBhcnJheVxuICpcbiAqIEBtZXRob2QgY29tYmluZVxuICogQHBhcmFtIHtTb2xpZGl0eVBhcmFtfSBwYXJhbSB3aXRoIHdoaWNoIHdlIHNob3VsZCBjb21iaW5lXG4gKiBAcGFyYW0ge1NvbGlkaXR5UGFyYW19IHJlc3VsdCBvZiBjb21iaW5hdGlvblxuICovXG5Tb2xpZGl0eVBhcmFtLnByb3RvdHlwZS5jb21iaW5lID0gZnVuY3Rpb24gKHBhcmFtKSB7XG4gICAgcmV0dXJuIG5ldyBTb2xpZGl0eVBhcmFtKHRoaXMudmFsdWUgKyBwYXJhbS52YWx1ZSk7IFxufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgY2FsbGVkIHRvIGNoZWNrIGlmIHBhcmFtIGhhcyBkeW5hbWljIHNpemUuXG4gKiBJZiBpdCBoYXMsIGl0IHJldHVybnMgdHJ1ZSwgb3RoZXJ3aXNlIGZhbHNlXG4gKlxuICogQG1ldGhvZCBpc0R5bmFtaWNcbiAqIEByZXR1cm5zIHtCb29sZWFufVxuICovXG5Tb2xpZGl0eVBhcmFtLnByb3RvdHlwZS5pc0R5bmFtaWMgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMudmFsdWUubGVuZ3RoID4gNjQgfHwgdGhpcy5vZmZzZXQgIT09IHVuZGVmaW5lZDtcbn07XG5cbi8qKlxuICogVGhpcyBtZXRob2Qgc2hvdWxkIGJlIGNhbGxlZCB0byB0cmFuc2Zvcm0gb2Zmc2V0IHRvIGJ5dGVzXG4gKlxuICogQG1ldGhvZCBvZmZzZXRBc0J5dGVzXG4gKiBAcmV0dXJucyB7U3RyaW5nfSBieXRlcyByZXByZXNlbnRhdGlvbiBvZiBvZmZzZXRcbiAqL1xuU29saWRpdHlQYXJhbS5wcm90b3R5cGUub2Zmc2V0QXNCeXRlcyA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gIXRoaXMuaXNEeW5hbWljKCkgPyAnJyA6IHV0aWxzLnBhZExlZnQodXRpbHMudG9Ud29zQ29tcGxlbWVudCh0aGlzLm9mZnNldCkudG9TdHJpbmcoMTYpLCA2NCk7XG59O1xuXG4vKipcbiAqIFRoaXMgbWV0aG9kIHNob3VsZCBiZSBjYWxsZWQgdG8gZ2V0IHN0YXRpYyBwYXJ0IG9mIHBhcmFtXG4gKlxuICogQG1ldGhvZCBzdGF0aWNQYXJ0XG4gKiBAcmV0dXJucyB7U3RyaW5nfSBvZmZzZXQgaWYgaXQgaXMgYSBkeW5hbWljIHBhcmFtLCBvdGhlcndpc2UgdmFsdWVcbiAqL1xuU29saWRpdHlQYXJhbS5wcm90b3R5cGUuc3RhdGljUGFydCA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoIXRoaXMuaXNEeW5hbWljKCkpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWU7IFxuICAgIH0gXG4gICAgcmV0dXJuIHRoaXMub2Zmc2V0QXNCeXRlcygpO1xufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgY2FsbGVkIHRvIGdldCBkeW5hbWljIHBhcnQgb2YgcGFyYW1cbiAqXG4gKiBAbWV0aG9kIGR5bmFtaWNQYXJ0XG4gKiBAcmV0dXJucyB7U3RyaW5nfSByZXR1cm5zIGEgdmFsdWUgaWYgaXQgaXMgYSBkeW5hbWljIHBhcmFtLCBvdGhlcndpc2UgZW1wdHkgc3RyaW5nXG4gKi9cblNvbGlkaXR5UGFyYW0ucHJvdG90eXBlLmR5bmFtaWNQYXJ0ID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLmlzRHluYW1pYygpID8gdGhpcy52YWx1ZSA6ICcnO1xufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgY2FsbGVkIHRvIGVuY29kZSBwYXJhbVxuICpcbiAqIEBtZXRob2QgZW5jb2RlXG4gKiBAcmV0dXJucyB7U3RyaW5nfVxuICovXG5Tb2xpZGl0eVBhcmFtLnByb3RvdHlwZS5lbmNvZGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGljUGFydCgpICsgdGhpcy5keW5hbWljUGFydCgpO1xufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgY2FsbGVkIHRvIGVuY29kZSBhcnJheSBvZiBwYXJhbXNcbiAqXG4gKiBAbWV0aG9kIGVuY29kZUxpc3RcbiAqIEBwYXJhbSB7QXJyYXlbU29saWRpdHlQYXJhbV19IHBhcmFtc1xuICogQHJldHVybnMge1N0cmluZ31cbiAqL1xuU29saWRpdHlQYXJhbS5lbmNvZGVMaXN0ID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICAgIFxuICAgIC8vIHVwZGF0aW5nIG9mZnNldHNcbiAgICB2YXIgdG90YWxPZmZzZXQgPSBwYXJhbXMubGVuZ3RoICogMzI7XG4gICAgdmFyIG9mZnNldFBhcmFtcyA9IHBhcmFtcy5tYXAoZnVuY3Rpb24gKHBhcmFtKSB7XG4gICAgICAgIGlmICghcGFyYW0uaXNEeW5hbWljKCkpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXJhbTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgb2Zmc2V0ID0gdG90YWxPZmZzZXQ7XG4gICAgICAgIHRvdGFsT2Zmc2V0ICs9IHBhcmFtLmR5bmFtaWNQYXJ0TGVuZ3RoKCk7XG4gICAgICAgIHJldHVybiBwYXJhbS53aXRoT2Zmc2V0KG9mZnNldCk7XG4gICAgfSk7XG5cbiAgICAvLyBlbmNvZGUgZXZlcnl0aGluZyFcbiAgICByZXR1cm4gb2Zmc2V0UGFyYW1zLnJlZHVjZShmdW5jdGlvbiAocmVzdWx0LCBwYXJhbSkge1xuICAgICAgICByZXR1cm4gcmVzdWx0ICsgcGFyYW0uZHluYW1pY1BhcnQoKTtcbiAgICB9LCBvZmZzZXRQYXJhbXMucmVkdWNlKGZ1bmN0aW9uIChyZXN1bHQsIHBhcmFtKSB7XG4gICAgICAgIHJldHVybiByZXN1bHQgKyBwYXJhbS5zdGF0aWNQYXJ0KCk7XG4gICAgfSwgJycpKTtcbn07XG5cbi8qKlxuICogVGhpcyBtZXRob2Qgc2hvdWxkIGJlIHVzZWQgdG8gZGVjb2RlIHBsYWluIChzdGF0aWMpIHNvbGlkaXR5IHBhcmFtIGF0IGdpdmVuIGluZGV4XG4gKlxuICogQG1ldGhvZCBkZWNvZGVQYXJhbVxuICogQHBhcmFtIHtTdHJpbmd9IGJ5dGVzXG4gKiBAcGFyYW0ge051bWJlcn0gaW5kZXhcbiAqIEByZXR1cm5zIHtTb2xpZGl0eVBhcmFtfVxuICovXG5Tb2xpZGl0eVBhcmFtLmRlY29kZVBhcmFtID0gZnVuY3Rpb24gKGJ5dGVzLCBpbmRleCkge1xuICAgIGluZGV4ID0gaW5kZXggfHwgMDtcbiAgICByZXR1cm4gbmV3IFNvbGlkaXR5UGFyYW0oYnl0ZXMuc3Vic3RyKGluZGV4ICogNjQsIDY0KSk7IFxufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgY2FsbGVkIHRvIGdldCBvZmZzZXQgdmFsdWUgZnJvbSBieXRlcyBhdCBnaXZlbiBpbmRleFxuICpcbiAqIEBtZXRob2QgZ2V0T2Zmc2V0XG4gKiBAcGFyYW0ge1N0cmluZ30gYnl0ZXNcbiAqIEBwYXJhbSB7TnVtYmVyfSBpbmRleFxuICogQHJldHVybnMge051bWJlcn0gb2Zmc2V0IGFzIG51bWJlclxuICovXG52YXIgZ2V0T2Zmc2V0ID0gZnVuY3Rpb24gKGJ5dGVzLCBpbmRleCkge1xuICAgIC8vIHdlIGNhbiBkbyB0aGlzIGNhdXNlIG9mZnNldCBpcyByYXRoZXIgc21hbGxcbiAgICByZXR1cm4gcGFyc2VJbnQoJzB4JyArIGJ5dGVzLnN1YnN0cihpbmRleCAqIDY0LCA2NCkpO1xufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgY2FsbGVkIHRvIGRlY29kZSBzb2xpZGl0eSBieXRlcyBwYXJhbSBhdCBnaXZlbiBpbmRleFxuICpcbiAqIEBtZXRob2QgZGVjb2RlQnl0ZXNcbiAqIEBwYXJhbSB7U3RyaW5nfSBieXRlc1xuICogQHBhcmFtIHtOdW1iZXJ9IGluZGV4XG4gKiBAcmV0dXJucyB7U29saWRpdHlQYXJhbX1cbiAqL1xuU29saWRpdHlQYXJhbS5kZWNvZGVCeXRlcyA9IGZ1bmN0aW9uIChieXRlcywgaW5kZXgpIHtcbiAgICBpbmRleCA9IGluZGV4IHx8IDA7XG4gICAgLy9UT0RPIGFkZCBzdXBwb3J0IGZvciBzdHJpbmdzIGxvbmdlciB0aGFuIDMyIGJ5dGVzXG4gICAgLy92YXIgbGVuZ3RoID0gcGFyc2VJbnQoJzB4JyArIGJ5dGVzLnN1YnN0cihvZmZzZXQgKiA2NCwgNjQpKTtcblxuICAgIHZhciBvZmZzZXQgPSBnZXRPZmZzZXQoYnl0ZXMsIGluZGV4KTtcblxuICAgIC8vIDIgKiAsIGNhdXNlIHdlIGFsc28gcGFyc2UgbGVuZ3RoXG4gICAgcmV0dXJuIG5ldyBTb2xpZGl0eVBhcmFtKGJ5dGVzLnN1YnN0cihvZmZzZXQgKiAyLCAyICogNjQpLCAwKTtcbn07XG5cbi8qKlxuICogVGhpcyBtZXRob2Qgc2hvdWxkIGJlIHVzZWQgdG8gZGVjb2RlIHNvbGlkaXR5IGFycmF5IGF0IGdpdmVuIGluZGV4XG4gKlxuICogQG1ldGhvZCBkZWNvZGVBcnJheVxuICogQHBhcmFtIHtTdHJpbmd9IGJ5dGVzXG4gKiBAcGFyYW0ge051bWJlcn0gaW5kZXhcbiAqIEByZXR1cm5zIHtTb2xpZGl0eVBhcmFtfVxuICovXG5Tb2xpZGl0eVBhcmFtLmRlY29kZUFycmF5ID0gZnVuY3Rpb24gKGJ5dGVzLCBpbmRleCkge1xuICAgIGluZGV4ID0gaW5kZXggfHwgMDtcbiAgICB2YXIgb2Zmc2V0ID0gZ2V0T2Zmc2V0KGJ5dGVzLCBpbmRleCk7XG4gICAgdmFyIGxlbmd0aCA9IHBhcnNlSW50KCcweCcgKyBieXRlcy5zdWJzdHIob2Zmc2V0ICogMiwgNjQpKTtcbiAgICByZXR1cm4gbmV3IFNvbGlkaXR5UGFyYW0oYnl0ZXMuc3Vic3RyKG9mZnNldCAqIDIsIChsZW5ndGggKyAxKSAqIDY0KSwgMCk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFNvbGlkaXR5UGFyYW07XG5cbiIsIid1c2Ugc3RyaWN0JztcblxuLy8gZ28gZW52IGRvZXNuJ3QgaGF2ZSBhbmQgbmVlZCBYTUxIdHRwUmVxdWVzdFxuaWYgKHR5cGVvZiBYTUxIdHRwUmVxdWVzdCA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBleHBvcnRzLlhNTEh0dHBSZXF1ZXN0ID0ge307XG59IGVsc2Uge1xuICAgIGV4cG9ydHMuWE1MSHR0cFJlcXVlc3QgPSBYTUxIdHRwUmVxdWVzdDsgLy8ganNoaW50IGlnbm9yZTpsaW5lXG59XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqIEBmaWxlIGNvbmZpZy5qc1xuICogQGF1dGhvcnM6XG4gKiAgIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbi8qKlxuICogVXRpbHNcbiAqIFxuICogQG1vZHVsZSB1dGlsc1xuICovXG5cbi8qKlxuICogVXRpbGl0eSBmdW5jdGlvbnNcbiAqIFxuICogQGNsYXNzIFt1dGlsc10gY29uZmlnXG4gKiBAY29uc3RydWN0b3JcbiAqL1xuXG4vLy8gcmVxdWlyZWQgdG8gZGVmaW5lIEVUSF9CSUdOVU1CRVJfUk9VTkRJTkdfTU9ERVxudmFyIEJpZ051bWJlciA9IHJlcXVpcmUoJ2JpZ251bWJlci5qcycpO1xuXG52YXIgRVRIX1VOSVRTID0gW1xuICAgICd3ZWknLFxuICAgICdrd2VpJyxcbiAgICAnTXdlaScsXG4gICAgJ0d3ZWknLFxuICAgICdzemFibycsXG4gICAgJ2Zpbm5leScsXG4gICAgJ2ZlbXRvZXRoZXInLFxuICAgICdwaWNvZXRoZXInLFxuICAgICduYW5vZXRoZXInLFxuICAgICdtaWNyb2V0aGVyJyxcbiAgICAnbWlsbGlldGhlcicsXG4gICAgJ25hbm8nLFxuICAgICdtaWNybycsXG4gICAgJ21pbGxpJyxcbiAgICAnZXRoZXInLFxuICAgICdncmFuZCcsXG4gICAgJ01ldGhlcicsXG4gICAgJ0dldGhlcicsXG4gICAgJ1RldGhlcicsXG4gICAgJ1BldGhlcicsXG4gICAgJ0VldGhlcicsXG4gICAgJ1pldGhlcicsXG4gICAgJ1lldGhlcicsXG4gICAgJ05ldGhlcicsXG4gICAgJ0RldGhlcicsXG4gICAgJ1ZldGhlcicsXG4gICAgJ1VldGhlcidcbl07XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIEVUSF9QQURESU5HOiAzMixcbiAgICBFVEhfU0lHTkFUVVJFX0xFTkdUSDogNCxcbiAgICBFVEhfVU5JVFM6IEVUSF9VTklUUyxcbiAgICBFVEhfQklHTlVNQkVSX1JPVU5ESU5HX01PREU6IHsgUk9VTkRJTkdfTU9ERTogQmlnTnVtYmVyLlJPVU5EX0RPV04gfSxcbiAgICBFVEhfUE9MTElOR19USU1FT1VUOiAxMDAwLFxuICAgIGRlZmF1bHRCbG9jazogJ2xhdGVzdCcsXG4gICAgZGVmYXVsdEFjY291bnQ6IHVuZGVmaW5lZFxufTtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogXG4gKiBAZmlsZSBzaGEzLmpzXG4gKiBAYXV0aG9yIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbnZhciB1dGlscyA9IHJlcXVpcmUoJy4vdXRpbHMnKTtcbnZhciBzaGEzID0gcmVxdWlyZSgnY3J5cHRvLWpzL3NoYTMnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoc3RyLCBpc05ldykge1xuICAgIGlmIChzdHIuc3Vic3RyKDAsIDIpID09PSAnMHgnICYmICFpc05ldykge1xuICAgICAgICBjb25zb2xlLndhcm4oJ3JlcXVpcmVtZW50IG9mIHVzaW5nIHdlYjMuZnJvbUFzY2lpIGJlZm9yZSBzaGEzIGlzIGRlcHJlY2F0ZWQnKTtcbiAgICAgICAgY29uc29sZS53YXJuKCduZXcgdXNhZ2U6IFxcJ3dlYjMuc2hhMyhcImhlbGxvXCIpXFwnJyk7XG4gICAgICAgIGNvbnNvbGUud2Fybignc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9ldGhlcmV1bS93ZWIzLmpzL3B1bGwvMjA1Jyk7XG4gICAgICAgIGNvbnNvbGUud2FybignaWYgeW91IG5lZWQgdG8gaGFzaCBoZXggdmFsdWUsIHlvdSBjYW4gZG8gXFwnc2hhMyhcIjB4ZmZmXCIsIHRydWUpXFwnJyk7XG4gICAgICAgIHN0ciA9IHV0aWxzLnRvQXNjaWkoc3RyKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc2hhMyhzdHIsIHtcbiAgICAgICAgb3V0cHV0TGVuZ3RoOiAyNTZcbiAgICB9KS50b1N0cmluZygpO1xufTtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogXG4gKiBAZmlsZSB1dGlscy5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG4vKipcbiAqIFV0aWxzXG4gKiBcbiAqIEBtb2R1bGUgdXRpbHNcbiAqL1xuXG4vKipcbiAqIFV0aWxpdHkgZnVuY3Rpb25zXG4gKiBcbiAqIEBjbGFzcyBbdXRpbHNdIHV0aWxzXG4gKiBAY29uc3RydWN0b3JcbiAqL1xuXG52YXIgQmlnTnVtYmVyID0gcmVxdWlyZSgnYmlnbnVtYmVyLmpzJyk7XG5cbnZhciB1bml0TWFwID0ge1xuICAgICd3ZWknOiAgICAgICAgICAnMScsXG4gICAgJ2t3ZWknOiAgICAgICAgICcxMDAwJyxcbiAgICAnYWRhJzogICAgICAgICAgJzEwMDAnLFxuICAgICdmZW10b2V0aGVyJzogICAnMTAwMCcsXG4gICAgJ213ZWknOiAgICAgICAgICcxMDAwMDAwJyxcbiAgICAnYmFiYmFnZSc6ICAgICAgJzEwMDAwMDAnLFxuICAgICdwaWNvZXRoZXInOiAgICAnMTAwMDAwMCcsXG4gICAgJ2d3ZWknOiAgICAgICAgICcxMDAwMDAwMDAwJyxcbiAgICAnc2hhbm5vbic6ICAgICAgJzEwMDAwMDAwMDAnLFxuICAgICduYW5vZXRoZXInOiAgICAnMTAwMDAwMDAwMCcsXG4gICAgJ25hbm8nOiAgICAgICAgICcxMDAwMDAwMDAwJyxcbiAgICAnc3phYm8nOiAgICAgICAgJzEwMDAwMDAwMDAwMDAnLFxuICAgICdtaWNyb2V0aGVyJzogICAnMTAwMDAwMDAwMDAwMCcsXG4gICAgJ21pY3JvJzogICAgICAgICcxMDAwMDAwMDAwMDAwJyxcbiAgICAnZmlubmV5JzogICAgICAgJzEwMDAwMDAwMDAwMDAwMDAnLFxuICAgICdtaWxsaWV0aGVyJzogICAgJzEwMDAwMDAwMDAwMDAwMDAnLFxuICAgICdtaWxsaSc6ICAgICAgICAgJzEwMDAwMDAwMDAwMDAwMDAnLFxuICAgICdldGhlcic6ICAgICAgICAnMTAwMDAwMDAwMDAwMDAwMDAwMCcsXG4gICAgJ2tldGhlcic6ICAgICAgICcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwJyxcbiAgICAnZ3JhbmQnOiAgICAgICAgJzEwMDAwMDAwMDAwMDAwMDAwMDAwMDAnLFxuICAgICdlaW5zdGVpbic6ICAgICAnMTAwMDAwMDAwMDAwMDAwMDAwMDAwMCcsXG4gICAgJ21ldGhlcic6ICAgICAgICcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwJyxcbiAgICAnZ2V0aGVyJzogICAgICAgJzEwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAnLFxuICAgICd0ZXRoZXInOiAgICAgICAnMTAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMCdcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBwYWQgc3RyaW5nIHRvIGV4cGVjdGVkIGxlbmd0aFxuICpcbiAqIEBtZXRob2QgcGFkTGVmdFxuICogQHBhcmFtIHtTdHJpbmd9IHN0cmluZyB0byBiZSBwYWRkZWRcbiAqIEBwYXJhbSB7TnVtYmVyfSBjaGFyYWN0ZXJzIHRoYXQgcmVzdWx0IHN0cmluZyBzaG91bGQgaGF2ZVxuICogQHBhcmFtIHtTdHJpbmd9IHNpZ24sIGJ5IGRlZmF1bHQgMFxuICogQHJldHVybnMge1N0cmluZ30gcmlnaHQgYWxpZ25lZCBzdHJpbmdcbiAqL1xudmFyIHBhZExlZnQgPSBmdW5jdGlvbiAoc3RyaW5nLCBjaGFycywgc2lnbikge1xuICAgIHJldHVybiBuZXcgQXJyYXkoY2hhcnMgLSBzdHJpbmcubGVuZ3RoICsgMSkuam9pbihzaWduID8gc2lnbiA6IFwiMFwiKSArIHN0cmluZztcbn07XG5cbi8qKiBcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZ2V0IHN0aW5nIGZyb20gaXQncyBoZXggcmVwcmVzZW50YXRpb25cbiAqXG4gKiBAbWV0aG9kIHRvQXNjaWlcbiAqIEBwYXJhbSB7U3RyaW5nfSBzdHJpbmcgaW4gaGV4XG4gKiBAcmV0dXJucyB7U3RyaW5nfSBhc2NpaSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgaGV4IHZhbHVlXG4gKi9cbnZhciB0b0FzY2lpID0gZnVuY3Rpb24oaGV4KSB7XG4vLyBGaW5kIHRlcm1pbmF0aW9uXG4gICAgdmFyIHN0ciA9IFwiXCI7XG4gICAgdmFyIGkgPSAwLCBsID0gaGV4Lmxlbmd0aDtcbiAgICBpZiAoaGV4LnN1YnN0cmluZygwLCAyKSA9PT0gJzB4Jykge1xuICAgICAgICBpID0gMjtcbiAgICB9XG4gICAgZm9yICg7IGkgPCBsOyBpKz0yKSB7XG4gICAgICAgIHZhciBjb2RlID0gcGFyc2VJbnQoaGV4LnN1YnN0cihpLCAyKSwgMTYpO1xuICAgICAgICBpZiAoY29kZSA9PT0gMCkge1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cblxuICAgICAgICBzdHIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShjb2RlKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc3RyO1xufTtcbiAgICBcbi8qKlxuICogU2hvbGQgYmUgY2FsbGVkIHRvIGdldCBoZXggcmVwcmVzZW50YXRpb24gKHByZWZpeGVkIGJ5IDB4KSBvZiBhc2NpaSBzdHJpbmcgXG4gKlxuICogQG1ldGhvZCB0b0hleE5hdGl2ZVxuICogQHBhcmFtIHtTdHJpbmd9IHN0cmluZ1xuICogQHJldHVybnMge1N0cmluZ30gaGV4IHJlcHJlc2VudGF0aW9uIG9mIGlucHV0IHN0cmluZ1xuICovXG52YXIgdG9IZXhOYXRpdmUgPSBmdW5jdGlvbihzdHIpIHtcbiAgICB2YXIgaGV4ID0gXCJcIjtcbiAgICBmb3IodmFyIGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBuID0gc3RyLmNoYXJDb2RlQXQoaSkudG9TdHJpbmcoMTYpO1xuICAgICAgICBoZXggKz0gbi5sZW5ndGggPCAyID8gJzAnICsgbiA6IG47XG4gICAgfVxuXG4gICAgcmV0dXJuIGhleDtcbn07XG5cbi8qKlxuICogU2hvbGQgYmUgY2FsbGVkIHRvIGdldCBoZXggcmVwcmVzZW50YXRpb24gKHByZWZpeGVkIGJ5IDB4KSBvZiBhc2NpaSBzdHJpbmcgXG4gKlxuICogQG1ldGhvZCBmcm9tQXNjaWlcbiAqIEBwYXJhbSB7U3RyaW5nfSBzdHJpbmdcbiAqIEBwYXJhbSB7TnVtYmVyfSBvcHRpb25hbCBwYWRkaW5nXG4gKiBAcmV0dXJucyB7U3RyaW5nfSBoZXggcmVwcmVzZW50YXRpb24gb2YgaW5wdXQgc3RyaW5nXG4gKi9cbnZhciBmcm9tQXNjaWkgPSBmdW5jdGlvbihzdHIsIHBhZCkge1xuICAgIHBhZCA9IHBhZCA9PT0gdW5kZWZpbmVkID8gMCA6IHBhZDtcbiAgICB2YXIgaGV4ID0gdG9IZXhOYXRpdmUoc3RyKTtcbiAgICB3aGlsZSAoaGV4Lmxlbmd0aCA8IHBhZCoyKVxuICAgICAgICBoZXggKz0gXCIwMFwiO1xuICAgIHJldHVybiBcIjB4XCIgKyBoZXg7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGNyZWF0ZSBmdWxsIGZ1bmN0aW9uL2V2ZW50IG5hbWUgZnJvbSBqc29uIGFiaVxuICpcbiAqIEBtZXRob2QgdHJhbnNmb3JtVG9GdWxsTmFtZVxuICogQHBhcmFtIHtPYmplY3R9IGpzb24tYWJpXG4gKiBAcmV0dXJuIHtTdHJpbmd9IGZ1bGwgZm5jdGlvbi9ldmVudCBuYW1lXG4gKi9cbnZhciB0cmFuc2Zvcm1Ub0Z1bGxOYW1lID0gZnVuY3Rpb24gKGpzb24pIHtcbiAgICBpZiAoanNvbi5uYW1lLmluZGV4T2YoJygnKSAhPT0gLTEpIHtcbiAgICAgICAgcmV0dXJuIGpzb24ubmFtZTtcbiAgICB9XG5cbiAgICB2YXIgdHlwZU5hbWUgPSBqc29uLmlucHV0cy5tYXAoZnVuY3Rpb24oaSl7cmV0dXJuIGkudHlwZTsgfSkuam9pbigpO1xuICAgIHJldHVybiBqc29uLm5hbWUgKyAnKCcgKyB0eXBlTmFtZSArICcpJztcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBnZXQgZGlzcGxheSBuYW1lIG9mIGNvbnRyYWN0IGZ1bmN0aW9uXG4gKiBcbiAqIEBtZXRob2QgZXh0cmFjdERpc3BsYXlOYW1lXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZSBvZiBmdW5jdGlvbi9ldmVudFxuICogQHJldHVybnMge1N0cmluZ30gZGlzcGxheSBuYW1lIGZvciBmdW5jdGlvbi9ldmVudCBlZy4gbXVsdGlwbHkodWludDI1NikgLT4gbXVsdGlwbHlcbiAqL1xudmFyIGV4dHJhY3REaXNwbGF5TmFtZSA9IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgdmFyIGxlbmd0aCA9IG5hbWUuaW5kZXhPZignKCcpOyBcbiAgICByZXR1cm4gbGVuZ3RoICE9PSAtMSA/IG5hbWUuc3Vic3RyKDAsIGxlbmd0aCkgOiBuYW1lO1xufTtcblxuLy8vIEByZXR1cm5zIG92ZXJsb2FkZWQgcGFydCBvZiBmdW5jdGlvbi9ldmVudCBuYW1lXG52YXIgZXh0cmFjdFR5cGVOYW1lID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAvLy8gVE9ETzogbWFrZSBpdCBpbnZ1bG5lcmFibGVcbiAgICB2YXIgbGVuZ3RoID0gbmFtZS5pbmRleE9mKCcoJyk7XG4gICAgcmV0dXJuIGxlbmd0aCAhPT0gLTEgPyBuYW1lLnN1YnN0cihsZW5ndGggKyAxLCBuYW1lLmxlbmd0aCAtIDEgLSAobGVuZ3RoICsgMSkpLnJlcGxhY2UoJyAnLCAnJykgOiBcIlwiO1xufTtcblxuLyoqXG4gKiBDb252ZXJ0cyB2YWx1ZSB0byBpdCdzIGRlY2ltYWwgcmVwcmVzZW50YXRpb24gaW4gc3RyaW5nXG4gKlxuICogQG1ldGhvZCB0b0RlY2ltYWxcbiAqIEBwYXJhbSB7U3RyaW5nfE51bWJlcnxCaWdOdW1iZXJ9XG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKi9cbnZhciB0b0RlY2ltYWwgPSBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICByZXR1cm4gdG9CaWdOdW1iZXIodmFsdWUpLnRvTnVtYmVyKCk7XG59O1xuXG4vKipcbiAqIENvbnZlcnRzIHZhbHVlIHRvIGl0J3MgaGV4IHJlcHJlc2VudGF0aW9uXG4gKlxuICogQG1ldGhvZCBmcm9tRGVjaW1hbFxuICogQHBhcmFtIHtTdHJpbmd8TnVtYmVyfEJpZ051bWJlcn1cbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xudmFyIGZyb21EZWNpbWFsID0gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgdmFyIG51bWJlciA9IHRvQmlnTnVtYmVyKHZhbHVlKTtcbiAgICB2YXIgcmVzdWx0ID0gbnVtYmVyLnRvU3RyaW5nKDE2KTtcblxuICAgIHJldHVybiBudW1iZXIubGVzc1RoYW4oMCkgPyAnLTB4JyArIHJlc3VsdC5zdWJzdHIoMSkgOiAnMHgnICsgcmVzdWx0O1xufTtcblxuLyoqXG4gKiBBdXRvIGNvbnZlcnRzIGFueSBnaXZlbiB2YWx1ZSBpbnRvIGl0J3MgaGV4IHJlcHJlc2VudGF0aW9uLlxuICpcbiAqIEFuZCBldmVuIHN0cmluZ2lmeXMgb2JqZWN0cyBiZWZvcmUuXG4gKlxuICogQG1ldGhvZCB0b0hleFxuICogQHBhcmFtIHtTdHJpbmd8TnVtYmVyfEJpZ051bWJlcnxPYmplY3R9XG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKi9cbnZhciB0b0hleCA9IGZ1bmN0aW9uICh2YWwpIHtcbiAgICAvKmpzaGludCBtYXhjb21wbGV4aXR5OjcgKi9cblxuICAgIGlmIChpc0Jvb2xlYW4odmFsKSlcbiAgICAgICAgcmV0dXJuIGZyb21EZWNpbWFsKCt2YWwpO1xuXG4gICAgaWYgKGlzQmlnTnVtYmVyKHZhbCkpXG4gICAgICAgIHJldHVybiBmcm9tRGVjaW1hbCh2YWwpO1xuXG4gICAgaWYgKGlzT2JqZWN0KHZhbCkpXG4gICAgICAgIHJldHVybiBmcm9tQXNjaWkoSlNPTi5zdHJpbmdpZnkodmFsKSk7XG5cbiAgICAvLyBpZiBpdHMgYSBuZWdhdGl2ZSBudW1iZXIsIHBhc3MgaXQgdGhyb3VnaCBmcm9tRGVjaW1hbFxuICAgIGlmIChpc1N0cmluZyh2YWwpKSB7XG4gICAgICAgIGlmICh2YWwuaW5kZXhPZignLTB4JykgPT09IDApXG4gICAgICAgICAgIHJldHVybiBmcm9tRGVjaW1hbCh2YWwpO1xuICAgICAgICBlbHNlIGlmICghaXNGaW5pdGUodmFsKSlcbiAgICAgICAgICAgIHJldHVybiBmcm9tQXNjaWkodmFsKTtcbiAgICB9XG5cbiAgICByZXR1cm4gZnJvbURlY2ltYWwodmFsKTtcbn07XG5cbi8qKlxuICogUmV0dXJucyB2YWx1ZSBvZiB1bml0IGluIFdlaVxuICpcbiAqIEBtZXRob2QgZ2V0VmFsdWVPZlVuaXRcbiAqIEBwYXJhbSB7U3RyaW5nfSB1bml0IHRoZSB1bml0IHRvIGNvbnZlcnQgdG8sIGRlZmF1bHQgZXRoZXJcbiAqIEByZXR1cm5zIHtCaWdOdW1iZXJ9IHZhbHVlIG9mIHRoZSB1bml0IChpbiBXZWkpXG4gKiBAdGhyb3dzIGVycm9yIGlmIHRoZSB1bml0IGlzIG5vdCBjb3JyZWN0OndcbiAqL1xudmFyIGdldFZhbHVlT2ZVbml0ID0gZnVuY3Rpb24gKHVuaXQpIHtcbiAgICB1bml0ID0gdW5pdCA/IHVuaXQudG9Mb3dlckNhc2UoKSA6ICdldGhlcic7XG4gICAgdmFyIHVuaXRWYWx1ZSA9IHVuaXRNYXBbdW5pdF07XG4gICAgaWYgKHVuaXRWYWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVGhpcyB1bml0IGRvZXNuXFwndCBleGlzdHMsIHBsZWFzZSB1c2UgdGhlIG9uZSBvZiB0aGUgZm9sbG93aW5nIHVuaXRzJyArIEpTT04uc3RyaW5naWZ5KHVuaXRNYXAsIG51bGwsIDIpKTtcbiAgICB9XG4gICAgcmV0dXJuIG5ldyBCaWdOdW1iZXIodW5pdFZhbHVlLCAxMCk7XG59O1xuXG4vKipcbiAqIFRha2VzIGEgbnVtYmVyIG9mIHdlaSBhbmQgY29udmVydHMgaXQgdG8gYW55IG90aGVyIGV0aGVyIHVuaXQuXG4gKlxuICogUG9zc2libGUgdW5pdHMgYXJlOlxuICogICBTSSBTaG9ydCAgIFNJIEZ1bGwgICAgICAgIEVmZmlneSAgICAgICBPdGhlclxuICogLSBrd2VpICAgICAgIGZlbXRvZXRoZXIgICAgIGFkYVxuICogLSBtd2VpICAgICAgIHBpY29ldGhlciAgICAgIGJhYmJhZ2VcbiAqIC0gZ3dlaSAgICAgICBuYW5vZXRoZXIgICAgICBzaGFubm9uICAgICAgbmFub1xuICogLSAtLSAgICAgICAgIG1pY3JvZXRoZXIgICAgIHN6YWJvICAgICAgICBtaWNyb1xuICogLSAtLSAgICAgICAgIG1pbGxpZXRoZXIgICAgIGZpbm5leSAgICAgICBtaWxsaVxuICogLSBldGhlciAgICAgIC0tICAgICAgICAgICAgIC0tXG4gKiAtIGtldGhlciAgICAgICAgICAgICAgICAgICAgZWluc3RlaW4gICAgIGdyYW5kIFxuICogLSBtZXRoZXJcbiAqIC0gZ2V0aGVyXG4gKiAtIHRldGhlclxuICpcbiAqIEBtZXRob2QgZnJvbVdlaVxuICogQHBhcmFtIHtOdW1iZXJ8U3RyaW5nfSBudW1iZXIgY2FuIGJlIGEgbnVtYmVyLCBudW1iZXIgc3RyaW5nIG9yIGEgSEVYIG9mIGEgZGVjaW1hbFxuICogQHBhcmFtIHtTdHJpbmd9IHVuaXQgdGhlIHVuaXQgdG8gY29udmVydCB0bywgZGVmYXVsdCBldGhlclxuICogQHJldHVybiB7U3RyaW5nfE9iamVjdH0gV2hlbiBnaXZlbiBhIEJpZ051bWJlciBvYmplY3QgaXQgcmV0dXJucyBvbmUgYXMgd2VsbCwgb3RoZXJ3aXNlIGEgbnVtYmVyXG4qL1xudmFyIGZyb21XZWkgPSBmdW5jdGlvbihudW1iZXIsIHVuaXQpIHtcbiAgICB2YXIgcmV0dXJuVmFsdWUgPSB0b0JpZ051bWJlcihudW1iZXIpLmRpdmlkZWRCeShnZXRWYWx1ZU9mVW5pdCh1bml0KSk7XG5cbiAgICByZXR1cm4gaXNCaWdOdW1iZXIobnVtYmVyKSA/IHJldHVyblZhbHVlIDogcmV0dXJuVmFsdWUudG9TdHJpbmcoMTApOyBcbn07XG5cbi8qKlxuICogVGFrZXMgYSBudW1iZXIgb2YgYSB1bml0IGFuZCBjb252ZXJ0cyBpdCB0byB3ZWkuXG4gKlxuICogUG9zc2libGUgdW5pdHMgYXJlOlxuICogICBTSSBTaG9ydCAgIFNJIEZ1bGwgICAgICAgIEVmZmlneSAgICAgICBPdGhlclxuICogLSBrd2VpICAgICAgIGZlbXRvZXRoZXIgICAgIGFkYVxuICogLSBtd2VpICAgICAgIHBpY29ldGhlciAgICAgIGJhYmJhZ2UgICAgICAgXG4gKiAtIGd3ZWkgICAgICAgbmFub2V0aGVyICAgICAgc2hhbm5vbiAgICAgIG5hbm9cbiAqIC0gLS0gICAgICAgICBtaWNyb2V0aGVyICAgICBzemFibyAgICAgICAgbWljcm9cbiAqIC0gLS0gICAgICAgICBtaWxsaWV0aGVyICAgICBmaW5uZXkgICAgICAgbWlsbGlcbiAqIC0gZXRoZXIgICAgICAtLSAgICAgICAgICAgICAtLVxuICogLSBrZXRoZXIgICAgICAgICAgICAgICAgICAgIGVpbnN0ZWluICAgICBncmFuZCBcbiAqIC0gbWV0aGVyXG4gKiAtIGdldGhlclxuICogLSB0ZXRoZXJcbiAqXG4gKiBAbWV0aG9kIHRvV2VpXG4gKiBAcGFyYW0ge051bWJlcnxTdHJpbmd8QmlnTnVtYmVyfSBudW1iZXIgY2FuIGJlIGEgbnVtYmVyLCBudW1iZXIgc3RyaW5nIG9yIGEgSEVYIG9mIGEgZGVjaW1hbFxuICogQHBhcmFtIHtTdHJpbmd9IHVuaXQgdGhlIHVuaXQgdG8gY29udmVydCBmcm9tLCBkZWZhdWx0IGV0aGVyXG4gKiBAcmV0dXJuIHtTdHJpbmd8T2JqZWN0fSBXaGVuIGdpdmVuIGEgQmlnTnVtYmVyIG9iamVjdCBpdCByZXR1cm5zIG9uZSBhcyB3ZWxsLCBvdGhlcndpc2UgYSBudW1iZXJcbiovXG52YXIgdG9XZWkgPSBmdW5jdGlvbihudW1iZXIsIHVuaXQpIHtcbiAgICB2YXIgcmV0dXJuVmFsdWUgPSB0b0JpZ051bWJlcihudW1iZXIpLnRpbWVzKGdldFZhbHVlT2ZVbml0KHVuaXQpKTtcblxuICAgIHJldHVybiBpc0JpZ051bWJlcihudW1iZXIpID8gcmV0dXJuVmFsdWUgOiByZXR1cm5WYWx1ZS50b1N0cmluZygxMCk7IFxufTtcblxuLyoqXG4gKiBUYWtlcyBhbiBpbnB1dCBhbmQgdHJhbnNmb3JtcyBpdCBpbnRvIGFuIGJpZ251bWJlclxuICpcbiAqIEBtZXRob2QgdG9CaWdOdW1iZXJcbiAqIEBwYXJhbSB7TnVtYmVyfFN0cmluZ3xCaWdOdW1iZXJ9IGEgbnVtYmVyLCBzdHJpbmcsIEhFWCBzdHJpbmcgb3IgQmlnTnVtYmVyXG4gKiBAcmV0dXJuIHtCaWdOdW1iZXJ9IEJpZ051bWJlclxuKi9cbnZhciB0b0JpZ051bWJlciA9IGZ1bmN0aW9uKG51bWJlcikge1xuICAgIC8qanNoaW50IG1heGNvbXBsZXhpdHk6NSAqL1xuICAgIG51bWJlciA9IG51bWJlciB8fCAwO1xuICAgIGlmIChpc0JpZ051bWJlcihudW1iZXIpKVxuICAgICAgICByZXR1cm4gbnVtYmVyO1xuXG4gICAgaWYgKGlzU3RyaW5nKG51bWJlcikgJiYgKG51bWJlci5pbmRleE9mKCcweCcpID09PSAwIHx8IG51bWJlci5pbmRleE9mKCctMHgnKSA9PT0gMCkpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBCaWdOdW1iZXIobnVtYmVyLnJlcGxhY2UoJzB4JywnJyksIDE2KTtcbiAgICB9XG4gICBcbiAgICByZXR1cm4gbmV3IEJpZ051bWJlcihudW1iZXIudG9TdHJpbmcoMTApLCAxMCk7XG59O1xuXG4vKipcbiAqIFRha2VzIGFuZCBpbnB1dCB0cmFuc2Zvcm1zIGl0IGludG8gYmlnbnVtYmVyIGFuZCBpZiBpdCBpcyBuZWdhdGl2ZSB2YWx1ZSwgaW50byB0d28ncyBjb21wbGVtZW50XG4gKlxuICogQG1ldGhvZCB0b1R3b3NDb21wbGVtZW50XG4gKiBAcGFyYW0ge051bWJlcnxTdHJpbmd8QmlnTnVtYmVyfVxuICogQHJldHVybiB7QmlnTnVtYmVyfVxuICovXG52YXIgdG9Ud29zQ29tcGxlbWVudCA9IGZ1bmN0aW9uIChudW1iZXIpIHtcbiAgICB2YXIgYmlnTnVtYmVyID0gdG9CaWdOdW1iZXIobnVtYmVyKTtcbiAgICBpZiAoYmlnTnVtYmVyLmxlc3NUaGFuKDApKSB7XG4gICAgICAgIHJldHVybiBuZXcgQmlnTnVtYmVyKFwiZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZlwiLCAxNikucGx1cyhiaWdOdW1iZXIpLnBsdXMoMSk7XG4gICAgfVxuICAgIHJldHVybiBiaWdOdW1iZXI7XG59O1xuXG4vKipcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gc3RyaW5nIGlzIHN0cmljdGx5IGFuIGFkZHJlc3NcbiAqXG4gKiBAbWV0aG9kIGlzU3RyaWN0QWRkcmVzc1xuICogQHBhcmFtIHtTdHJpbmd9IGFkZHJlc3MgdGhlIGdpdmVuIEhFWCBhZHJlc3NcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4qL1xudmFyIGlzU3RyaWN0QWRkcmVzcyA9IGZ1bmN0aW9uIChhZGRyZXNzKSB7XG4gICAgcmV0dXJuIC9eMHhbMC05YS1mXXs0MH0kLy50ZXN0KGFkZHJlc3MpO1xufTtcblxuLyoqXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIHN0cmluZyBpcyBhbiBhZGRyZXNzXG4gKlxuICogQG1ldGhvZCBpc0FkZHJlc3NcbiAqIEBwYXJhbSB7U3RyaW5nfSBhZGRyZXNzIHRoZSBnaXZlbiBIRVggYWRyZXNzXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuKi9cbnZhciBpc0FkZHJlc3MgPSBmdW5jdGlvbiAoYWRkcmVzcykge1xuICAgIHJldHVybiAvXigweCk/WzAtOWEtZl17NDB9JC8udGVzdChhZGRyZXNzKTtcbn07XG5cbi8qKlxuICogVHJhbnNmb3JtcyBnaXZlbiBzdHJpbmcgdG8gdmFsaWQgMjAgYnl0ZXMtbGVuZ3RoIGFkZHJlcyB3aXRoIDB4IHByZWZpeFxuICpcbiAqIEBtZXRob2QgdG9BZGRyZXNzXG4gKiBAcGFyYW0ge1N0cmluZ30gYWRkcmVzc1xuICogQHJldHVybiB7U3RyaW5nfSBmb3JtYXR0ZWQgYWRkcmVzc1xuICovXG52YXIgdG9BZGRyZXNzID0gZnVuY3Rpb24gKGFkZHJlc3MpIHtcbiAgICBpZiAoaXNTdHJpY3RBZGRyZXNzKGFkZHJlc3MpKSB7XG4gICAgICAgIHJldHVybiBhZGRyZXNzO1xuICAgIH1cbiAgICBcbiAgICBpZiAoL15bMC05YS1mXXs0MH0kLy50ZXN0KGFkZHJlc3MpKSB7XG4gICAgICAgIHJldHVybiAnMHgnICsgYWRkcmVzcztcbiAgICB9XG5cbiAgICByZXR1cm4gJzB4JyArIHBhZExlZnQodG9IZXgoYWRkcmVzcykuc3Vic3RyKDIpLCA0MCk7XG59O1xuXG5cbi8qKlxuICogUmV0dXJucyB0cnVlIGlmIG9iamVjdCBpcyBCaWdOdW1iZXIsIG90aGVyd2lzZSBmYWxzZVxuICpcbiAqIEBtZXRob2QgaXNCaWdOdW1iZXJcbiAqIEBwYXJhbSB7T2JqZWN0fVxuICogQHJldHVybiB7Qm9vbGVhbn0gXG4gKi9cbnZhciBpc0JpZ051bWJlciA9IGZ1bmN0aW9uIChvYmplY3QpIHtcbiAgICByZXR1cm4gb2JqZWN0IGluc3RhbmNlb2YgQmlnTnVtYmVyIHx8XG4gICAgICAgIChvYmplY3QgJiYgb2JqZWN0LmNvbnN0cnVjdG9yICYmIG9iamVjdC5jb25zdHJ1Y3Rvci5uYW1lID09PSAnQmlnTnVtYmVyJyk7XG59O1xuXG4vKipcbiAqIFJldHVybnMgdHJ1ZSBpZiBvYmplY3QgaXMgc3RyaW5nLCBvdGhlcndpc2UgZmFsc2VcbiAqIFxuICogQG1ldGhvZCBpc1N0cmluZ1xuICogQHBhcmFtIHtPYmplY3R9XG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG52YXIgaXNTdHJpbmcgPSBmdW5jdGlvbiAob2JqZWN0KSB7XG4gICAgcmV0dXJuIHR5cGVvZiBvYmplY3QgPT09ICdzdHJpbmcnIHx8XG4gICAgICAgIChvYmplY3QgJiYgb2JqZWN0LmNvbnN0cnVjdG9yICYmIG9iamVjdC5jb25zdHJ1Y3Rvci5uYW1lID09PSAnU3RyaW5nJyk7XG59O1xuXG4vKipcbiAqIFJldHVybnMgdHJ1ZSBpZiBvYmplY3QgaXMgZnVuY3Rpb24sIG90aGVyd2lzZSBmYWxzZVxuICpcbiAqIEBtZXRob2QgaXNGdW5jdGlvblxuICogQHBhcmFtIHtPYmplY3R9XG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG52YXIgaXNGdW5jdGlvbiA9IGZ1bmN0aW9uIChvYmplY3QpIHtcbiAgICByZXR1cm4gdHlwZW9mIG9iamVjdCA9PT0gJ2Z1bmN0aW9uJztcbn07XG5cbi8qKlxuICogUmV0dXJucyB0cnVlIGlmIG9iamVjdCBpcyBPYmpldCwgb3RoZXJ3aXNlIGZhbHNlXG4gKlxuICogQG1ldGhvZCBpc09iamVjdFxuICogQHBhcmFtIHtPYmplY3R9XG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG52YXIgaXNPYmplY3QgPSBmdW5jdGlvbiAob2JqZWN0KSB7XG4gICAgcmV0dXJuIHR5cGVvZiBvYmplY3QgPT09ICdvYmplY3QnO1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIHRydWUgaWYgb2JqZWN0IGlzIGJvb2xlYW4sIG90aGVyd2lzZSBmYWxzZVxuICpcbiAqIEBtZXRob2QgaXNCb29sZWFuXG4gKiBAcGFyYW0ge09iamVjdH1cbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbnZhciBpc0Jvb2xlYW4gPSBmdW5jdGlvbiAob2JqZWN0KSB7XG4gICAgcmV0dXJuIHR5cGVvZiBvYmplY3QgPT09ICdib29sZWFuJztcbn07XG5cbi8qKlxuICogUmV0dXJucyB0cnVlIGlmIG9iamVjdCBpcyBhcnJheSwgb3RoZXJ3aXNlIGZhbHNlXG4gKlxuICogQG1ldGhvZCBpc0FycmF5XG4gKiBAcGFyYW0ge09iamVjdH1cbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbnZhciBpc0FycmF5ID0gZnVuY3Rpb24gKG9iamVjdCkge1xuICAgIHJldHVybiBvYmplY3QgaW5zdGFuY2VvZiBBcnJheTsgXG59O1xuXG4vKipcbiAqIFJldHVybnMgdHJ1ZSBpZiBnaXZlbiBzdHJpbmcgaXMgdmFsaWQganNvbiBvYmplY3RcbiAqIFxuICogQG1ldGhvZCBpc0pzb25cbiAqIEBwYXJhbSB7U3RyaW5nfVxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqL1xudmFyIGlzSnNvbiA9IGZ1bmN0aW9uIChzdHIpIHtcbiAgICB0cnkge1xuICAgICAgICByZXR1cm4gISFKU09OLnBhcnNlKHN0cik7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgY2FsbGVkIHRvIGNoZWNrIGlmIHN0cmluZyBpcyB2YWxpZCBldGhlcmV1bSBJQkFOIG51bWJlclxuICogU3VwcG9ydHMgZGlyZWN0IGFuZCBpbmRpcmVjdCBJQkFOc1xuICpcbiAqIEBtZXRob2QgaXNJQkFOXG4gKiBAcGFyYW0ge1N0cmluZ31cbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbnZhciBpc0lCQU4gPSBmdW5jdGlvbiAoaWJhbikge1xuICAgIHJldHVybiAvXlhFWzAtOV17Mn0oRVRIWzAtOUEtWl17MTN9fFswLTlBLVpdezMwfSkkLy50ZXN0KGliYW4pO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgcGFkTGVmdDogcGFkTGVmdCxcbiAgICB0b0hleDogdG9IZXgsXG4gICAgdG9EZWNpbWFsOiB0b0RlY2ltYWwsXG4gICAgZnJvbURlY2ltYWw6IGZyb21EZWNpbWFsLFxuICAgIHRvQXNjaWk6IHRvQXNjaWksXG4gICAgZnJvbUFzY2lpOiBmcm9tQXNjaWksXG4gICAgdHJhbnNmb3JtVG9GdWxsTmFtZTogdHJhbnNmb3JtVG9GdWxsTmFtZSxcbiAgICBleHRyYWN0RGlzcGxheU5hbWU6IGV4dHJhY3REaXNwbGF5TmFtZSxcbiAgICBleHRyYWN0VHlwZU5hbWU6IGV4dHJhY3RUeXBlTmFtZSxcbiAgICB0b1dlaTogdG9XZWksXG4gICAgZnJvbVdlaTogZnJvbVdlaSxcbiAgICB0b0JpZ051bWJlcjogdG9CaWdOdW1iZXIsXG4gICAgdG9Ud29zQ29tcGxlbWVudDogdG9Ud29zQ29tcGxlbWVudCxcbiAgICB0b0FkZHJlc3M6IHRvQWRkcmVzcyxcbiAgICBpc0JpZ051bWJlcjogaXNCaWdOdW1iZXIsXG4gICAgaXNTdHJpY3RBZGRyZXNzOiBpc1N0cmljdEFkZHJlc3MsXG4gICAgaXNBZGRyZXNzOiBpc0FkZHJlc3MsXG4gICAgaXNGdW5jdGlvbjogaXNGdW5jdGlvbixcbiAgICBpc1N0cmluZzogaXNTdHJpbmcsXG4gICAgaXNPYmplY3Q6IGlzT2JqZWN0LFxuICAgIGlzQm9vbGVhbjogaXNCb29sZWFuLFxuICAgIGlzQXJyYXk6IGlzQXJyYXksXG4gICAgaXNKc29uOiBpc0pzb24sXG4gICAgaXNJQkFOOiBpc0lCQU5cbn07XG5cbiIsIm1vZHVsZS5leHBvcnRzPXtcbiAgICBcInZlcnNpb25cIjogXCIwLjUuMFwiXG59XG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBAZmlsZSB3ZWIzLmpzXG4gKiBAYXV0aG9yczpcbiAqICAgSmVmZnJleSBXaWxja2UgPGplZmZAZXRoZGV2LmNvbT5cbiAqICAgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiAgIE1hcmlhbiBPYW5jZWEgPG1hcmlhbkBldGhkZXYuY29tPlxuICogICBGYWJpYW4gVm9nZWxzdGVsbGVyIDxmYWJpYW5AZXRoZGV2LmNvbT5cbiAqICAgR2F2IFdvb2QgPGdAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTRcbiAqL1xuXG52YXIgdmVyc2lvbiA9IHJlcXVpcmUoJy4vdmVyc2lvbi5qc29uJyk7XG52YXIgbmV0ID0gcmVxdWlyZSgnLi93ZWIzL25ldCcpO1xudmFyIGV0aCA9IHJlcXVpcmUoJy4vd2ViMy9ldGgnKTtcbnZhciBkYiA9IHJlcXVpcmUoJy4vd2ViMy9kYicpO1xudmFyIHNoaCA9IHJlcXVpcmUoJy4vd2ViMy9zaGgnKTtcbnZhciB3YXRjaGVzID0gcmVxdWlyZSgnLi93ZWIzL3dhdGNoZXMnKTtcbnZhciBGaWx0ZXIgPSByZXF1aXJlKCcuL3dlYjMvZmlsdGVyJyk7XG52YXIgdXRpbHMgPSByZXF1aXJlKCcuL3V0aWxzL3V0aWxzJyk7XG52YXIgZm9ybWF0dGVycyA9IHJlcXVpcmUoJy4vd2ViMy9mb3JtYXR0ZXJzJyk7XG52YXIgUmVxdWVzdE1hbmFnZXIgPSByZXF1aXJlKCcuL3dlYjMvcmVxdWVzdG1hbmFnZXInKTtcbnZhciBjID0gcmVxdWlyZSgnLi91dGlscy9jb25maWcnKTtcbnZhciBQcm9wZXJ0eSA9IHJlcXVpcmUoJy4vd2ViMy9wcm9wZXJ0eScpO1xudmFyIEJhdGNoID0gcmVxdWlyZSgnLi93ZWIzL2JhdGNoJyk7XG52YXIgc2hhMyA9IHJlcXVpcmUoJy4vdXRpbHMvc2hhMycpO1xuXG52YXIgd2ViM1Byb3BlcnRpZXMgPSBbXG4gICAgbmV3IFByb3BlcnR5KHtcbiAgICAgICAgbmFtZTogJ3ZlcnNpb24uY2xpZW50JyxcbiAgICAgICAgZ2V0dGVyOiAnd2ViM19jbGllbnRWZXJzaW9uJ1xuICAgIH0pLFxuICAgIG5ldyBQcm9wZXJ0eSh7XG4gICAgICAgIG5hbWU6ICd2ZXJzaW9uLm5ldHdvcmsnLFxuICAgICAgICBnZXR0ZXI6ICduZXRfdmVyc2lvbicsXG4gICAgICAgIGlucHV0Rm9ybWF0dGVyOiB1dGlscy50b0RlY2ltYWxcbiAgICB9KSxcbiAgICBuZXcgUHJvcGVydHkoe1xuICAgICAgICBuYW1lOiAndmVyc2lvbi5ldGhlcmV1bScsXG4gICAgICAgIGdldHRlcjogJ2V0aF9wcm90b2NvbFZlcnNpb24nLFxuICAgICAgICBpbnB1dEZvcm1hdHRlcjogdXRpbHMudG9EZWNpbWFsXG4gICAgfSksXG4gICAgbmV3IFByb3BlcnR5KHtcbiAgICAgICAgbmFtZTogJ3ZlcnNpb24ud2hpc3BlcicsXG4gICAgICAgIGdldHRlcjogJ3NoaF92ZXJzaW9uJyxcbiAgICAgICAgaW5wdXRGb3JtYXR0ZXI6IHV0aWxzLnRvRGVjaW1hbFxuICAgIH0pXG5dO1xuXG4vLy8gY3JlYXRlcyBtZXRob2RzIGluIGEgZ2l2ZW4gb2JqZWN0IGJhc2VkIG9uIG1ldGhvZCBkZXNjcmlwdGlvbiBvbiBpbnB1dFxuLy8vIHNldHVwcyBhcGkgY2FsbHMgZm9yIHRoZXNlIG1ldGhvZHNcbnZhciBzZXR1cE1ldGhvZHMgPSBmdW5jdGlvbiAob2JqLCBtZXRob2RzKSB7XG4gICAgbWV0aG9kcy5mb3JFYWNoKGZ1bmN0aW9uIChtZXRob2QpIHtcbiAgICAgICAgbWV0aG9kLmF0dGFjaFRvT2JqZWN0KG9iaik7XG4gICAgfSk7XG59O1xuXG4vLy8gY3JlYXRlcyBwcm9wZXJ0aWVzIGluIGEgZ2l2ZW4gb2JqZWN0IGJhc2VkIG9uIHByb3BlcnRpZXMgZGVzY3JpcHRpb24gb24gaW5wdXRcbi8vLyBzZXR1cHMgYXBpIGNhbGxzIGZvciB0aGVzZSBwcm9wZXJ0aWVzXG52YXIgc2V0dXBQcm9wZXJ0aWVzID0gZnVuY3Rpb24gKG9iaiwgcHJvcGVydGllcykge1xuICAgIHByb3BlcnRpZXMuZm9yRWFjaChmdW5jdGlvbiAocHJvcGVydHkpIHtcbiAgICAgICAgcHJvcGVydHkuYXR0YWNoVG9PYmplY3Qob2JqKTtcbiAgICB9KTtcbn07XG5cbi8vLyBzZXR1cHMgd2ViMyBvYmplY3QsIGFuZCBpdCdzIGluLWJyb3dzZXIgZXhlY3V0ZWQgbWV0aG9kc1xudmFyIHdlYjMgPSB7fTtcbndlYjMucHJvdmlkZXJzID0ge307XG53ZWIzLnZlcnNpb24gPSB7fTtcbndlYjMudmVyc2lvbi5hcGkgPSB2ZXJzaW9uLnZlcnNpb247XG53ZWIzLmV0aCA9IHt9O1xuXG4vKmpzaGludCBtYXhwYXJhbXM6NCAqL1xud2ViMy5ldGguZmlsdGVyID0gZnVuY3Rpb24gKGZpbCwgZXZlbnRQYXJhbXMsIG9wdGlvbnMsIGZvcm1hdHRlcikge1xuXG4gICAgLy8gaWYgaXRzIGV2ZW50LCB0cmVhdCBpdCBkaWZmZXJlbnRseVxuICAgIC8vIFRPRE86IHNpbXBsaWZ5IGFuZCByZW1vdmVcbiAgICBpZiAoZmlsLl9pc0V2ZW50KSB7XG4gICAgICAgIHJldHVybiBmaWwoZXZlbnRQYXJhbXMsIG9wdGlvbnMpO1xuICAgIH1cblxuICAgIC8vIHdoYXQgb3V0cHV0TG9nRm9ybWF0dGVyPyB0aGF0J3Mgd3JvbmdcbiAgICAvL3JldHVybiBuZXcgRmlsdGVyKGZpbCwgd2F0Y2hlcy5ldGgoKSwgZm9ybWF0dGVycy5vdXRwdXRMb2dGb3JtYXR0ZXIpO1xuICAgIHJldHVybiBuZXcgRmlsdGVyKGZpbCwgd2F0Y2hlcy5ldGgoKSwgZm9ybWF0dGVyIHx8IGZvcm1hdHRlcnMub3V0cHV0TG9nRm9ybWF0dGVyKTtcbn07XG4vKmpzaGludCBtYXhwYXJhbXM6MyAqL1xuXG53ZWIzLnNoaCA9IHt9O1xud2ViMy5zaGguZmlsdGVyID0gZnVuY3Rpb24gKGZpbCkge1xuICAgIHJldHVybiBuZXcgRmlsdGVyKGZpbCwgd2F0Y2hlcy5zaGgoKSwgZm9ybWF0dGVycy5vdXRwdXRQb3N0Rm9ybWF0dGVyKTtcbn07XG53ZWIzLm5ldCA9IHt9O1xud2ViMy5kYiA9IHt9O1xud2ViMy5zZXRQcm92aWRlciA9IGZ1bmN0aW9uIChwcm92aWRlcikge1xuICAgIFJlcXVlc3RNYW5hZ2VyLmdldEluc3RhbmNlKCkuc2V0UHJvdmlkZXIocHJvdmlkZXIpO1xufTtcbndlYjMucmVzZXQgPSBmdW5jdGlvbiAoKSB7XG4gICAgUmVxdWVzdE1hbmFnZXIuZ2V0SW5zdGFuY2UoKS5yZXNldCgpO1xuICAgIGMuZGVmYXVsdEJsb2NrID0gJ2xhdGVzdCc7XG4gICAgYy5kZWZhdWx0QWNjb3VudCA9IHVuZGVmaW5lZDtcbn07XG53ZWIzLnRvSGV4ID0gdXRpbHMudG9IZXg7XG53ZWIzLnRvQXNjaWkgPSB1dGlscy50b0FzY2lpO1xud2ViMy5mcm9tQXNjaWkgPSB1dGlscy5mcm9tQXNjaWk7XG53ZWIzLnRvRGVjaW1hbCA9IHV0aWxzLnRvRGVjaW1hbDtcbndlYjMuZnJvbURlY2ltYWwgPSB1dGlscy5mcm9tRGVjaW1hbDtcbndlYjMudG9CaWdOdW1iZXIgPSB1dGlscy50b0JpZ051bWJlcjtcbndlYjMudG9XZWkgPSB1dGlscy50b1dlaTtcbndlYjMuZnJvbVdlaSA9IHV0aWxzLmZyb21XZWk7XG53ZWIzLmlzQWRkcmVzcyA9IHV0aWxzLmlzQWRkcmVzcztcbndlYjMuaXNJQkFOID0gdXRpbHMuaXNJQkFOO1xud2ViMy5zaGEzID0gc2hhMztcbndlYjMuY3JlYXRlQmF0Y2ggPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIG5ldyBCYXRjaCgpO1xufTtcblxuLy8gQUREIGRlZmF1bHRibG9ja1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KHdlYjMuZXRoLCAnZGVmYXVsdEJsb2NrJywge1xuICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gYy5kZWZhdWx0QmxvY2s7XG4gICAgfSxcbiAgICBzZXQ6IGZ1bmN0aW9uICh2YWwpIHtcbiAgICAgICAgYy5kZWZhdWx0QmxvY2sgPSB2YWw7XG4gICAgICAgIHJldHVybiB2YWw7XG4gICAgfVxufSk7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eSh3ZWIzLmV0aCwgJ2RlZmF1bHRBY2NvdW50Jywge1xuICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gYy5kZWZhdWx0QWNjb3VudDtcbiAgICB9LFxuICAgIHNldDogZnVuY3Rpb24gKHZhbCkge1xuICAgICAgICBjLmRlZmF1bHRBY2NvdW50ID0gdmFsO1xuICAgICAgICByZXR1cm4gdmFsO1xuICAgIH1cbn0pO1xuXG4vLy8gc2V0dXBzIGFsbCBhcGkgbWV0aG9kc1xuc2V0dXBQcm9wZXJ0aWVzKHdlYjMsIHdlYjNQcm9wZXJ0aWVzKTtcbnNldHVwTWV0aG9kcyh3ZWIzLm5ldCwgbmV0Lm1ldGhvZHMpO1xuc2V0dXBQcm9wZXJ0aWVzKHdlYjMubmV0LCBuZXQucHJvcGVydGllcyk7XG5zZXR1cE1ldGhvZHMod2ViMy5ldGgsIGV0aC5tZXRob2RzKTtcbnNldHVwUHJvcGVydGllcyh3ZWIzLmV0aCwgZXRoLnByb3BlcnRpZXMpO1xuc2V0dXBNZXRob2RzKHdlYjMuZGIsIGRiLm1ldGhvZHMpO1xuc2V0dXBNZXRob2RzKHdlYjMuc2hoLCBzaGgubWV0aG9kcyk7XG5cbm1vZHVsZS5leHBvcnRzID0gd2ViMztcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogXG4gKiBAZmlsZSBiYXRjaC5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgUmVxdWVzdE1hbmFnZXIgPSByZXF1aXJlKCcuL3JlcXVlc3RtYW5hZ2VyJyk7XG5cbnZhciBCYXRjaCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnJlcXVlc3RzID0gW107XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gYWRkIGNyZWF0ZSBuZXcgcmVxdWVzdCB0byBiYXRjaCByZXF1ZXN0XG4gKlxuICogQG1ldGhvZCBhZGRcbiAqIEBwYXJhbSB7T2JqZWN0fSBqc29ucnBjIHJlcXVldCBvYmplY3RcbiAqL1xuQmF0Y2gucHJvdG90eXBlLmFkZCA9IGZ1bmN0aW9uIChyZXF1ZXN0KSB7XG4gICAgdGhpcy5yZXF1ZXN0cy5wdXNoKHJlcXVlc3QpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGV4ZWN1dGUgYmF0Y2ggcmVxdWVzdFxuICpcbiAqIEBtZXRob2QgZXhlY3V0ZVxuICovXG5CYXRjaC5wcm90b3R5cGUuZXhlY3V0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgcmVxdWVzdHMgPSB0aGlzLnJlcXVlc3RzO1xuICAgIFJlcXVlc3RNYW5hZ2VyLmdldEluc3RhbmNlKCkuc2VuZEJhdGNoKHJlcXVlc3RzLCBmdW5jdGlvbiAoZXJyLCByZXN1bHRzKSB7XG4gICAgICAgIHJlc3VsdHMgPSByZXN1bHRzIHx8IFtdO1xuICAgICAgICByZXF1ZXN0cy5tYXAoZnVuY3Rpb24gKHJlcXVlc3QsIGluZGV4KSB7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0c1tpbmRleF0gfHwge307XG4gICAgICAgIH0pLm1hcChmdW5jdGlvbiAocmVzdWx0LCBpbmRleCkge1xuICAgICAgICAgICAgcmV0dXJuIHJlcXVlc3RzW2luZGV4XS5mb3JtYXQgPyByZXF1ZXN0c1tpbmRleF0uZm9ybWF0KHJlc3VsdC5yZXN1bHQpIDogcmVzdWx0LnJlc3VsdDtcbiAgICAgICAgfSkuZm9yRWFjaChmdW5jdGlvbiAocmVzdWx0LCBpbmRleCkge1xuICAgICAgICAgICAgaWYgKHJlcXVlc3RzW2luZGV4XS5jYWxsYmFjaykge1xuICAgICAgICAgICAgICAgIHJlcXVlc3RzW2luZGV4XS5jYWxsYmFjayhlcnIsIHJlc3VsdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH0pOyBcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gQmF0Y2g7XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqIFxuICogQGZpbGUgY29udHJhY3QuanNcbiAqIEBhdXRob3IgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE0XG4gKi9cblxudmFyIHdlYjMgPSByZXF1aXJlKCcuLi93ZWIzJyk7IFxudmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMvdXRpbHMnKTtcbnZhciBjb2RlciA9IHJlcXVpcmUoJy4uL3NvbGlkaXR5L2NvZGVyJyk7XG52YXIgU29saWRpdHlFdmVudCA9IHJlcXVpcmUoJy4vZXZlbnQnKTtcbnZhciBTb2xpZGl0eUZ1bmN0aW9uID0gcmVxdWlyZSgnLi9mdW5jdGlvbicpO1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZW5jb2RlIGNvbnN0cnVjdG9yIHBhcmFtc1xuICpcbiAqIEBtZXRob2QgZW5jb2RlQ29uc3RydWN0b3JQYXJhbXNcbiAqIEBwYXJhbSB7QXJyYXl9IGFiaVxuICogQHBhcmFtIHtBcnJheX0gY29uc3RydWN0b3IgcGFyYW1zXG4gKi9cbnZhciBlbmNvZGVDb25zdHJ1Y3RvclBhcmFtcyA9IGZ1bmN0aW9uIChhYmksIHBhcmFtcykge1xuICAgIHJldHVybiBhYmkuZmlsdGVyKGZ1bmN0aW9uIChqc29uKSB7XG4gICAgICAgIHJldHVybiBqc29uLnR5cGUgPT09ICdjb25zdHJ1Y3RvcicgJiYganNvbi5pbnB1dHMubGVuZ3RoID09PSBwYXJhbXMubGVuZ3RoO1xuICAgIH0pLm1hcChmdW5jdGlvbiAoanNvbikge1xuICAgICAgICByZXR1cm4ganNvbi5pbnB1dHMubWFwKGZ1bmN0aW9uIChpbnB1dCkge1xuICAgICAgICAgICAgcmV0dXJuIGlucHV0LnR5cGU7XG4gICAgICAgIH0pO1xuICAgIH0pLm1hcChmdW5jdGlvbiAodHlwZXMpIHtcbiAgICAgICAgcmV0dXJuIGNvZGVyLmVuY29kZVBhcmFtcyh0eXBlcywgcGFyYW1zKTtcbiAgICB9KVswXSB8fCAnJztcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBhZGQgZnVuY3Rpb25zIHRvIGNvbnRyYWN0IG9iamVjdFxuICpcbiAqIEBtZXRob2QgYWRkRnVuY3Rpb25zVG9Db250cmFjdFxuICogQHBhcmFtIHtDb250cmFjdH0gY29udHJhY3RcbiAqIEBwYXJhbSB7QXJyYXl9IGFiaVxuICovXG52YXIgYWRkRnVuY3Rpb25zVG9Db250cmFjdCA9IGZ1bmN0aW9uIChjb250cmFjdCwgYWJpKSB7XG4gICAgYWJpLmZpbHRlcihmdW5jdGlvbiAoanNvbikge1xuICAgICAgICByZXR1cm4ganNvbi50eXBlID09PSAnZnVuY3Rpb24nO1xuICAgIH0pLm1hcChmdW5jdGlvbiAoanNvbikge1xuICAgICAgICByZXR1cm4gbmV3IFNvbGlkaXR5RnVuY3Rpb24oanNvbiwgY29udHJhY3QuYWRkcmVzcyk7XG4gICAgfSkuZm9yRWFjaChmdW5jdGlvbiAoZikge1xuICAgICAgICBmLmF0dGFjaFRvQ29udHJhY3QoY29udHJhY3QpO1xuICAgIH0pO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGFkZCBldmVudHMgdG8gY29udHJhY3Qgb2JqZWN0XG4gKlxuICogQG1ldGhvZCBhZGRFdmVudHNUb0NvbnRyYWN0XG4gKiBAcGFyYW0ge0NvbnRyYWN0fSBjb250cmFjdFxuICogQHBhcmFtIHtBcnJheX0gYWJpXG4gKi9cbnZhciBhZGRFdmVudHNUb0NvbnRyYWN0ID0gZnVuY3Rpb24gKGNvbnRyYWN0LCBhYmkpIHtcbiAgICBhYmkuZmlsdGVyKGZ1bmN0aW9uIChqc29uKSB7XG4gICAgICAgIHJldHVybiBqc29uLnR5cGUgPT09ICdldmVudCc7XG4gICAgfSkubWFwKGZ1bmN0aW9uIChqc29uKSB7XG4gICAgICAgIHJldHVybiBuZXcgU29saWRpdHlFdmVudChqc29uLCBjb250cmFjdC5hZGRyZXNzKTtcbiAgICB9KS5mb3JFYWNoKGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUuYXR0YWNoVG9Db250cmFjdChjb250cmFjdCk7XG4gICAgfSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gY3JlYXRlIG5ldyBDb250cmFjdEZhY3RvcnlcbiAqXG4gKiBAbWV0aG9kIGNvbnRyYWN0XG4gKiBAcGFyYW0ge0FycmF5fSBhYmlcbiAqIEByZXR1cm5zIHtDb250cmFjdEZhY3Rvcnl9IG5ldyBjb250cmFjdCBmYWN0b3J5XG4gKi9cbnZhciBjb250cmFjdCA9IGZ1bmN0aW9uIChhYmkpIHtcbiAgICByZXR1cm4gbmV3IENvbnRyYWN0RmFjdG9yeShhYmkpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGNyZWF0ZSBuZXcgQ29udHJhY3RGYWN0b3J5IGluc3RhbmNlXG4gKlxuICogQG1ldGhvZCBDb250cmFjdEZhY3RvcnlcbiAqIEBwYXJhbSB7QXJyYXl9IGFiaVxuICovXG52YXIgQ29udHJhY3RGYWN0b3J5ID0gZnVuY3Rpb24gKGFiaSkge1xuICAgIHRoaXMuYWJpID0gYWJpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGNyZWF0ZSBuZXcgY29udHJhY3Qgb24gYSBibG9ja2NoYWluXG4gKiBcbiAqIEBtZXRob2QgbmV3XG4gKiBAcGFyYW0ge0FueX0gY29udHJhY3QgY29uc3RydWN0b3IgcGFyYW0xIChvcHRpb25hbClcbiAqIEBwYXJhbSB7QW55fSBjb250cmFjdCBjb25zdHJ1Y3RvciBwYXJhbTIgKG9wdGlvbmFsKVxuICogQHBhcmFtIHtPYmplY3R9IGNvbnRyYWN0IHRyYW5zYWN0aW9uIG9iamVjdCAocmVxdWlyZWQpXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFja1xuICogQHJldHVybnMge0NvbnRyYWN0fSByZXR1cm5zIGNvbnRyYWN0IGlmIG5vIGNhbGxiYWNrIHdhcyBwYXNzZWQsXG4gKiBvdGhlcndpc2UgY2FsbHMgY2FsbGJhY2sgZnVuY3Rpb24gKGVyciwgY29udHJhY3QpXG4gKi9cbkNvbnRyYWN0RmFjdG9yeS5wcm90b3R5cGUubmV3ID0gZnVuY3Rpb24gKCkge1xuICAgIC8vIHBhcnNlIGFyZ3VtZW50c1xuICAgIHZhciBvcHRpb25zID0ge307IC8vIHJlcXVpcmVkIVxuICAgIHZhciBjYWxsYmFjaztcblxuICAgIHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKTtcbiAgICBpZiAodXRpbHMuaXNGdW5jdGlvbihhcmdzW2FyZ3MubGVuZ3RoIC0gMV0pKSB7XG4gICAgICAgIGNhbGxiYWNrID0gYXJncy5wb3AoKTtcbiAgICB9XG5cbiAgICB2YXIgbGFzdCA9IGFyZ3NbYXJncy5sZW5ndGggLSAxXTtcbiAgICBpZiAodXRpbHMuaXNPYmplY3QobGFzdCkgJiYgIXV0aWxzLmlzQXJyYXkobGFzdCkpIHtcbiAgICAgICAgb3B0aW9ucyA9IGFyZ3MucG9wKCk7XG4gICAgfVxuXG4gICAgLy8gdGhyb3cgYW4gZXJyb3IgaWYgdGhlcmUgYXJlIG5vIG9wdGlvbnNcblxuICAgIHZhciBieXRlcyA9IGVuY29kZUNvbnN0cnVjdG9yUGFyYW1zKHRoaXMuYWJpLCBhcmdzKTtcbiAgICBvcHRpb25zLmRhdGEgKz0gYnl0ZXM7XG5cbiAgICBpZiAoIWNhbGxiYWNrKSB7XG4gICAgICAgIHZhciBhZGRyZXNzID0gd2ViMy5ldGguc2VuZFRyYW5zYWN0aW9uKG9wdGlvbnMpO1xuICAgICAgICByZXR1cm4gdGhpcy5hdChhZGRyZXNzKTtcbiAgICB9XG4gIFxuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB3ZWIzLmV0aC5zZW5kVHJhbnNhY3Rpb24ob3B0aW9ucywgZnVuY3Rpb24gKGVyciwgYWRkcmVzcykge1xuICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICBjYWxsYmFjayhlcnIpO1xuICAgICAgICB9XG4gICAgICAgIHNlbGYuYXQoYWRkcmVzcywgY2FsbGJhY2spOyBcbiAgICB9KTsgXG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZ2V0IGFjY2VzcyB0byBleGlzdGluZyBjb250cmFjdCBvbiBhIGJsb2NrY2hhaW5cbiAqXG4gKiBAbWV0aG9kIGF0XG4gKiBAcGFyYW0ge0FkZHJlc3N9IGNvbnRyYWN0IGFkZHJlc3MgKHJlcXVpcmVkKVxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sge29wdGlvbmFsKVxuICogQHJldHVybnMge0NvbnRyYWN0fSByZXR1cm5zIGNvbnRyYWN0IGlmIG5vIGNhbGxiYWNrIHdhcyBwYXNzZWQsXG4gKiBvdGhlcndpc2UgY2FsbHMgY2FsbGJhY2sgZnVuY3Rpb24gKGVyciwgY29udHJhY3QpXG4gKi9cbkNvbnRyYWN0RmFjdG9yeS5wcm90b3R5cGUuYXQgPSBmdW5jdGlvbiAoYWRkcmVzcywgY2FsbGJhY2spIHtcbiAgICAvLyBUT0RPOiBhZGRyZXNzIGlzIHJlcXVpcmVkXG4gICAgXG4gICAgaWYgKGNhbGxiYWNrKSB7XG4gICAgICAgIGNhbGxiYWNrKG51bGwsIG5ldyBDb250cmFjdCh0aGlzLmFiaSwgYWRkcmVzcykpO1xuICAgIH0gXG4gICAgcmV0dXJuIG5ldyBDb250cmFjdCh0aGlzLmFiaSwgYWRkcmVzcyk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gY3JlYXRlIG5ldyBjb250cmFjdCBpbnN0YW5jZVxuICpcbiAqIEBtZXRob2QgQ29udHJhY3RcbiAqIEBwYXJhbSB7QXJyYXl9IGFiaVxuICogQHBhcmFtIHtBZGRyZXNzfSBjb250cmFjdCBhZGRyZXNzXG4gKi9cbnZhciBDb250cmFjdCA9IGZ1bmN0aW9uIChhYmksIGFkZHJlc3MpIHtcbiAgICB0aGlzLmFkZHJlc3MgPSBhZGRyZXNzO1xuICAgIGFkZEZ1bmN0aW9uc1RvQ29udHJhY3QodGhpcywgYWJpKTtcbiAgICBhZGRFdmVudHNUb0NvbnRyYWN0KHRoaXMsIGFiaSk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNvbnRyYWN0O1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBAZmlsZSBkYi5qc1xuICogQGF1dGhvcnM6XG4gKiAgIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbnZhciBNZXRob2QgPSByZXF1aXJlKCcuL21ldGhvZCcpO1xuXG52YXIgcHV0U3RyaW5nID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ3B1dFN0cmluZycsXG4gICAgY2FsbDogJ2RiX3B1dFN0cmluZycsXG4gICAgcGFyYW1zOiAzXG59KTtcblxuXG52YXIgZ2V0U3RyaW5nID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2dldFN0cmluZycsXG4gICAgY2FsbDogJ2RiX2dldFN0cmluZycsXG4gICAgcGFyYW1zOiAyXG59KTtcblxudmFyIHB1dEhleCA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdwdXRIZXgnLFxuICAgIGNhbGw6ICdkYl9wdXRIZXgnLFxuICAgIHBhcmFtczogM1xufSk7XG5cbnZhciBnZXRIZXggPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnZ2V0SGV4JyxcbiAgICBjYWxsOiAnZGJfZ2V0SGV4JyxcbiAgICBwYXJhbXM6IDJcbn0pO1xuXG52YXIgbWV0aG9kcyA9IFtcbiAgICBwdXRTdHJpbmcsIGdldFN0cmluZywgcHV0SGV4LCBnZXRIZXhcbl07XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIG1ldGhvZHM6IG1ldGhvZHNcbn07XG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBcbiAqIEBmaWxlIGVycm9ycy5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBJbnZhbGlkTnVtYmVyT2ZQYXJhbXM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBFcnJvcignSW52YWxpZCBudW1iZXIgb2YgaW5wdXQgcGFyYW1ldGVycycpO1xuICAgIH0sXG4gICAgSW52YWxpZENvbm5lY3Rpb246IGZ1bmN0aW9uIChob3N0KXtcbiAgICAgICAgcmV0dXJuIG5ldyBFcnJvcignQ09OTkVDVElPTiBFUlJPUjogQ291bGRuXFwndCBjb25uZWN0IHRvIG5vZGUgJysgaG9zdCArJywgaXMgaXQgcnVubmluZz8nKTtcbiAgICB9LFxuICAgIEludmFsaWRQcm92aWRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gbmV3IEVycm9yKCdQcm92aWRvciBub3Qgc2V0IG9yIGludmFsaWQnKTtcbiAgICB9LFxuICAgIEludmFsaWRSZXNwb25zZTogZnVuY3Rpb24gKHJlc3VsdCl7XG4gICAgICAgIHZhciBtZXNzYWdlID0gISFyZXN1bHQgJiYgISFyZXN1bHQuZXJyb3IgJiYgISFyZXN1bHQuZXJyb3IubWVzc2FnZSA/IHJlc3VsdC5lcnJvci5tZXNzYWdlIDogJ0ludmFsaWQgSlNPTiBSUEMgcmVzcG9uc2UnO1xuICAgICAgICByZXR1cm4gbmV3IEVycm9yKG1lc3NhZ2UpO1xuICAgIH1cbn07XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqXG4gKiBAZmlsZSBldGguanNcbiAqIEBhdXRob3IgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiBAYXV0aG9yIEZhYmlhbiBWb2dlbHN0ZWxsZXIgPGZhYmlhbkBldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbi8qKlxuICogV2ViM1xuICpcbiAqIEBtb2R1bGUgd2ViM1xuICovXG5cbi8qKlxuICogRXRoIG1ldGhvZHMgYW5kIHByb3BlcnRpZXNcbiAqXG4gKiBBbiBleGFtcGxlIG1ldGhvZCBvYmplY3QgY2FuIGxvb2sgYXMgZm9sbG93czpcbiAqXG4gKiAgICAgIHtcbiAqICAgICAgbmFtZTogJ2dldEJsb2NrJyxcbiAqICAgICAgY2FsbDogYmxvY2tDYWxsLFxuICogICAgICBwYXJhbXM6IDIsXG4gKiAgICAgIG91dHB1dEZvcm1hdHRlcjogZm9ybWF0dGVycy5vdXRwdXRCbG9ja0Zvcm1hdHRlcixcbiAqICAgICAgaW5wdXRGb3JtYXR0ZXI6IFsgLy8gY2FuIGJlIGEgZm9ybWF0dGVyIGZ1bmNpdG9uIG9yIGFuIGFycmF5IG9mIGZ1bmN0aW9ucy4gV2hlcmUgZWFjaCBpdGVtIGluIHRoZSBhcnJheSB3aWxsIGJlIHVzZWQgZm9yIG9uZSBwYXJhbWV0ZXJcbiAqICAgICAgICAgICB1dGlscy50b0hleCwgLy8gZm9ybWF0cyBwYXJhbXRlciAxXG4gKiAgICAgICAgICAgZnVuY3Rpb24ocGFyYW0peyByZXR1cm4gISFwYXJhbTsgfSAvLyBmb3JtYXRzIHBhcmFtdGVyIDJcbiAqICAgICAgICAgXVxuICogICAgICAgfSxcbiAqXG4gKiBAY2xhc3MgW3dlYjNdIGV0aFxuICogQGNvbnN0cnVjdG9yXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBmb3JtYXR0ZXJzID0gcmVxdWlyZSgnLi9mb3JtYXR0ZXJzJyk7XG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy91dGlscycpO1xudmFyIE1ldGhvZCA9IHJlcXVpcmUoJy4vbWV0aG9kJyk7XG52YXIgUHJvcGVydHkgPSByZXF1aXJlKCcuL3Byb3BlcnR5Jyk7XG5cbnZhciBibG9ja0NhbGwgPSBmdW5jdGlvbiAoYXJncykge1xuICAgIHJldHVybiAodXRpbHMuaXNTdHJpbmcoYXJnc1swXSkgJiYgYXJnc1swXS5pbmRleE9mKCcweCcpID09PSAwKSA/IFwiZXRoX2dldEJsb2NrQnlIYXNoXCIgOiBcImV0aF9nZXRCbG9ja0J5TnVtYmVyXCI7XG59O1xuXG52YXIgdHJhbnNhY3Rpb25Gcm9tQmxvY2tDYWxsID0gZnVuY3Rpb24gKGFyZ3MpIHtcbiAgICByZXR1cm4gKHV0aWxzLmlzU3RyaW5nKGFyZ3NbMF0pICYmIGFyZ3NbMF0uaW5kZXhPZignMHgnKSA9PT0gMCkgPyAnZXRoX2dldFRyYW5zYWN0aW9uQnlCbG9ja0hhc2hBbmRJbmRleCcgOiAnZXRoX2dldFRyYW5zYWN0aW9uQnlCbG9ja051bWJlckFuZEluZGV4Jztcbn07XG5cbnZhciB1bmNsZUNhbGwgPSBmdW5jdGlvbiAoYXJncykge1xuICAgIHJldHVybiAodXRpbHMuaXNTdHJpbmcoYXJnc1swXSkgJiYgYXJnc1swXS5pbmRleE9mKCcweCcpID09PSAwKSA/ICdldGhfZ2V0VW5jbGVCeUJsb2NrSGFzaEFuZEluZGV4JyA6ICdldGhfZ2V0VW5jbGVCeUJsb2NrTnVtYmVyQW5kSW5kZXgnO1xufTtcblxudmFyIGdldEJsb2NrVHJhbnNhY3Rpb25Db3VudENhbGwgPSBmdW5jdGlvbiAoYXJncykge1xuICAgIHJldHVybiAodXRpbHMuaXNTdHJpbmcoYXJnc1swXSkgJiYgYXJnc1swXS5pbmRleE9mKCcweCcpID09PSAwKSA/ICdldGhfZ2V0QmxvY2tUcmFuc2FjdGlvbkNvdW50QnlIYXNoJyA6ICdldGhfZ2V0QmxvY2tUcmFuc2FjdGlvbkNvdW50QnlOdW1iZXInO1xufTtcblxudmFyIHVuY2xlQ291bnRDYWxsID0gZnVuY3Rpb24gKGFyZ3MpIHtcbiAgICByZXR1cm4gKHV0aWxzLmlzU3RyaW5nKGFyZ3NbMF0pICYmIGFyZ3NbMF0uaW5kZXhPZignMHgnKSA9PT0gMCkgPyAnZXRoX2dldFVuY2xlQ291bnRCeUJsb2NrSGFzaCcgOiAnZXRoX2dldFVuY2xlQ291bnRCeUJsb2NrTnVtYmVyJztcbn07XG5cbi8vLyBAcmV0dXJucyBhbiBhcnJheSBvZiBvYmplY3RzIGRlc2NyaWJpbmcgd2ViMy5ldGggYXBpIG1ldGhvZHNcblxudmFyIGdldEJhbGFuY2UgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnZ2V0QmFsYW5jZScsXG4gICAgY2FsbDogJ2V0aF9nZXRCYWxhbmNlJyxcbiAgICBwYXJhbXM6IDIsXG4gICAgaW5wdXRGb3JtYXR0ZXI6IFt1dGlscy50b0FkZHJlc3MsIGZvcm1hdHRlcnMuaW5wdXREZWZhdWx0QmxvY2tOdW1iZXJGb3JtYXR0ZXJdLFxuICAgIG91dHB1dEZvcm1hdHRlcjogZm9ybWF0dGVycy5vdXRwdXRCaWdOdW1iZXJGb3JtYXR0ZXJcbn0pO1xuXG52YXIgZ2V0U3RvcmFnZUF0ID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2dldFN0b3JhZ2VBdCcsXG4gICAgY2FsbDogJ2V0aF9nZXRTdG9yYWdlQXQnLFxuICAgIHBhcmFtczogMyxcbiAgICBpbnB1dEZvcm1hdHRlcjogW251bGwsIHV0aWxzLnRvSGV4LCBmb3JtYXR0ZXJzLmlucHV0RGVmYXVsdEJsb2NrTnVtYmVyRm9ybWF0dGVyXVxufSk7XG5cbnZhciBnZXRDb2RlID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2dldENvZGUnLFxuICAgIGNhbGw6ICdldGhfZ2V0Q29kZScsXG4gICAgcGFyYW1zOiAyLFxuICAgIGlucHV0Rm9ybWF0dGVyOiBbdXRpbHMudG9BZGRyZXNzLCBmb3JtYXR0ZXJzLmlucHV0RGVmYXVsdEJsb2NrTnVtYmVyRm9ybWF0dGVyXVxufSk7XG5cbnZhciBnZXRCbG9jayA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdnZXRCbG9jaycsXG4gICAgY2FsbDogYmxvY2tDYWxsLFxuICAgIHBhcmFtczogMixcbiAgICBpbnB1dEZvcm1hdHRlcjogW2Zvcm1hdHRlcnMuaW5wdXRCbG9ja051bWJlckZvcm1hdHRlciwgZnVuY3Rpb24gKHZhbCkgeyByZXR1cm4gISF2YWw7IH1dLFxuICAgIG91dHB1dEZvcm1hdHRlcjogZm9ybWF0dGVycy5vdXRwdXRCbG9ja0Zvcm1hdHRlclxufSk7XG5cbnZhciBnZXRVbmNsZSA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdnZXRVbmNsZScsXG4gICAgY2FsbDogdW5jbGVDYWxsLFxuICAgIHBhcmFtczogMixcbiAgICBpbnB1dEZvcm1hdHRlcjogW2Zvcm1hdHRlcnMuaW5wdXRCbG9ja051bWJlckZvcm1hdHRlciwgdXRpbHMudG9IZXhdLFxuICAgIG91dHB1dEZvcm1hdHRlcjogZm9ybWF0dGVycy5vdXRwdXRCbG9ja0Zvcm1hdHRlcixcblxufSk7XG5cbnZhciBnZXRDb21waWxlcnMgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnZ2V0Q29tcGlsZXJzJyxcbiAgICBjYWxsOiAnZXRoX2dldENvbXBpbGVycycsXG4gICAgcGFyYW1zOiAwXG59KTtcblxudmFyIGdldEJsb2NrVHJhbnNhY3Rpb25Db3VudCA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdnZXRCbG9ja1RyYW5zYWN0aW9uQ291bnQnLFxuICAgIGNhbGw6IGdldEJsb2NrVHJhbnNhY3Rpb25Db3VudENhbGwsXG4gICAgcGFyYW1zOiAxLFxuICAgIGlucHV0Rm9ybWF0dGVyOiBbZm9ybWF0dGVycy5pbnB1dEJsb2NrTnVtYmVyRm9ybWF0dGVyXSxcbiAgICBvdXRwdXRGb3JtYXR0ZXI6IHV0aWxzLnRvRGVjaW1hbFxufSk7XG5cbnZhciBnZXRCbG9ja1VuY2xlQ291bnQgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnZ2V0QmxvY2tVbmNsZUNvdW50JyxcbiAgICBjYWxsOiB1bmNsZUNvdW50Q2FsbCxcbiAgICBwYXJhbXM6IDEsXG4gICAgaW5wdXRGb3JtYXR0ZXI6IFtmb3JtYXR0ZXJzLmlucHV0QmxvY2tOdW1iZXJGb3JtYXR0ZXJdLFxuICAgIG91dHB1dEZvcm1hdHRlcjogdXRpbHMudG9EZWNpbWFsXG59KTtcblxudmFyIGdldFRyYW5zYWN0aW9uID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2dldFRyYW5zYWN0aW9uJyxcbiAgICBjYWxsOiAnZXRoX2dldFRyYW5zYWN0aW9uQnlIYXNoJyxcbiAgICBwYXJhbXM6IDEsXG4gICAgb3V0cHV0Rm9ybWF0dGVyOiBmb3JtYXR0ZXJzLm91dHB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyXG59KTtcblxudmFyIGdldFRyYW5zYWN0aW9uRnJvbUJsb2NrID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2dldFRyYW5zYWN0aW9uRnJvbUJsb2NrJyxcbiAgICBjYWxsOiB0cmFuc2FjdGlvbkZyb21CbG9ja0NhbGwsXG4gICAgcGFyYW1zOiAyLFxuICAgIGlucHV0Rm9ybWF0dGVyOiBbZm9ybWF0dGVycy5pbnB1dEJsb2NrTnVtYmVyRm9ybWF0dGVyLCB1dGlscy50b0hleF0sXG4gICAgb3V0cHV0Rm9ybWF0dGVyOiBmb3JtYXR0ZXJzLm91dHB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyXG59KTtcblxudmFyIGdldFRyYW5zYWN0aW9uQ291bnQgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnZ2V0VHJhbnNhY3Rpb25Db3VudCcsXG4gICAgY2FsbDogJ2V0aF9nZXRUcmFuc2FjdGlvbkNvdW50JyxcbiAgICBwYXJhbXM6IDIsXG4gICAgaW5wdXRGb3JtYXR0ZXI6IFtudWxsLCBmb3JtYXR0ZXJzLmlucHV0RGVmYXVsdEJsb2NrTnVtYmVyRm9ybWF0dGVyXSxcbiAgICBvdXRwdXRGb3JtYXR0ZXI6IHV0aWxzLnRvRGVjaW1hbFxufSk7XG5cbnZhciBzZW5kVHJhbnNhY3Rpb24gPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnc2VuZFRyYW5zYWN0aW9uJyxcbiAgICBjYWxsOiAnZXRoX3NlbmRUcmFuc2FjdGlvbicsXG4gICAgcGFyYW1zOiAxLFxuICAgIGlucHV0Rm9ybWF0dGVyOiBbZm9ybWF0dGVycy5pbnB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyXVxufSk7XG5cbnZhciBjYWxsID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2NhbGwnLFxuICAgIGNhbGw6ICdldGhfY2FsbCcsXG4gICAgcGFyYW1zOiAyLFxuICAgIGlucHV0Rm9ybWF0dGVyOiBbZm9ybWF0dGVycy5pbnB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyLCBmb3JtYXR0ZXJzLmlucHV0RGVmYXVsdEJsb2NrTnVtYmVyRm9ybWF0dGVyXVxufSk7XG5cbnZhciBlc3RpbWF0ZUdhcyA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdlc3RpbWF0ZUdhcycsXG4gICAgY2FsbDogJ2V0aF9lc3RpbWF0ZUdhcycsXG4gICAgcGFyYW1zOiAxLFxuICAgIGlucHV0Rm9ybWF0dGVyOiBbZm9ybWF0dGVycy5pbnB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyXSxcbiAgICBvdXRwdXRGb3JtYXR0ZXI6IHV0aWxzLnRvRGVjaW1hbFxufSk7XG5cbnZhciBjb21waWxlU29saWRpdHkgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnY29tcGlsZS5zb2xpZGl0eScsXG4gICAgY2FsbDogJ2V0aF9jb21waWxlU29saWRpdHknLFxuICAgIHBhcmFtczogMVxufSk7XG5cbnZhciBjb21waWxlTExMID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2NvbXBpbGUubGxsJyxcbiAgICBjYWxsOiAnZXRoX2NvbXBpbGVMTEwnLFxuICAgIHBhcmFtczogMVxufSk7XG5cbnZhciBjb21waWxlU2VycGVudCA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdjb21waWxlLnNlcnBlbnQnLFxuICAgIGNhbGw6ICdldGhfY29tcGlsZVNlcnBlbnQnLFxuICAgIHBhcmFtczogMVxufSk7XG5cbnZhciBzdWJtaXRXb3JrID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ3N1Ym1pdFdvcmsnLFxuICAgIGNhbGw6ICdldGhfc3VibWl0V29yaycsXG4gICAgcGFyYW1zOiAzXG59KTtcblxudmFyIGdldFdvcmsgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnZ2V0V29yaycsXG4gICAgY2FsbDogJ2V0aF9nZXRXb3JrJyxcbiAgICBwYXJhbXM6IDBcbn0pO1xuXG52YXIgbWV0aG9kcyA9IFtcbiAgICBnZXRCYWxhbmNlLFxuICAgIGdldFN0b3JhZ2VBdCxcbiAgICBnZXRDb2RlLFxuICAgIGdldEJsb2NrLFxuICAgIGdldFVuY2xlLFxuICAgIGdldENvbXBpbGVycyxcbiAgICBnZXRCbG9ja1RyYW5zYWN0aW9uQ291bnQsXG4gICAgZ2V0QmxvY2tVbmNsZUNvdW50LFxuICAgIGdldFRyYW5zYWN0aW9uLFxuICAgIGdldFRyYW5zYWN0aW9uRnJvbUJsb2NrLFxuICAgIGdldFRyYW5zYWN0aW9uQ291bnQsXG4gICAgY2FsbCxcbiAgICBlc3RpbWF0ZUdhcyxcbiAgICBzZW5kVHJhbnNhY3Rpb24sXG4gICAgY29tcGlsZVNvbGlkaXR5LFxuICAgIGNvbXBpbGVMTEwsXG4gICAgY29tcGlsZVNlcnBlbnQsXG4gICAgc3VibWl0V29yayxcbiAgICBnZXRXb3JrXG5dO1xuXG4vLy8gQHJldHVybnMgYW4gYXJyYXkgb2Ygb2JqZWN0cyBkZXNjcmliaW5nIHdlYjMuZXRoIGFwaSBwcm9wZXJ0aWVzXG5cblxuXG52YXIgcHJvcGVydGllcyA9IFtcbiAgICBuZXcgUHJvcGVydHkoe1xuICAgICAgICBuYW1lOiAnY29pbmJhc2UnLFxuICAgICAgICBnZXR0ZXI6ICdldGhfY29pbmJhc2UnXG4gICAgfSksXG4gICAgbmV3IFByb3BlcnR5KHtcbiAgICAgICAgbmFtZTogJ21pbmluZycsXG4gICAgICAgIGdldHRlcjogJ2V0aF9taW5pbmcnXG4gICAgfSksXG4gICAgbmV3IFByb3BlcnR5KHtcbiAgICAgICAgbmFtZTogJ2hhc2hyYXRlJyxcbiAgICAgICAgZ2V0dGVyOiAnZXRoX2hhc2hyYXRlJyxcbiAgICAgICAgb3V0cHV0Rm9ybWF0dGVyOiB1dGlscy50b0RlY2ltYWxcbiAgICB9KSxcbiAgICBuZXcgUHJvcGVydHkoe1xuICAgICAgICBuYW1lOiAnZ2FzUHJpY2UnLFxuICAgICAgICBnZXR0ZXI6ICdldGhfZ2FzUHJpY2UnLFxuICAgICAgICBvdXRwdXRGb3JtYXR0ZXI6IGZvcm1hdHRlcnMub3V0cHV0QmlnTnVtYmVyRm9ybWF0dGVyXG4gICAgfSksXG4gICAgbmV3IFByb3BlcnR5KHtcbiAgICAgICAgbmFtZTogJ2FjY291bnRzJyxcbiAgICAgICAgZ2V0dGVyOiAnZXRoX2FjY291bnRzJ1xuICAgIH0pLFxuICAgIG5ldyBQcm9wZXJ0eSh7XG4gICAgICAgIG5hbWU6ICdibG9ja051bWJlcicsXG4gICAgICAgIGdldHRlcjogJ2V0aF9ibG9ja051bWJlcicsXG4gICAgICAgIG91dHB1dEZvcm1hdHRlcjogdXRpbHMudG9EZWNpbWFsXG4gICAgfSlcbl07XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIG1ldGhvZHM6IG1ldGhvZHMsXG4gICAgcHJvcGVydGllczogcHJvcGVydGllc1xufTtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogXG4gKiBAZmlsZSBldmVudC5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTRcbiAqL1xuXG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy91dGlscycpO1xudmFyIGNvZGVyID0gcmVxdWlyZSgnLi4vc29saWRpdHkvY29kZXInKTtcbnZhciB3ZWIzID0gcmVxdWlyZSgnLi4vd2ViMycpO1xudmFyIGZvcm1hdHRlcnMgPSByZXF1aXJlKCcuL2Zvcm1hdHRlcnMnKTtcbnZhciBzaGEzID0gcmVxdWlyZSgnLi4vdXRpbHMvc2hhMycpO1xuXG4vKipcbiAqIFRoaXMgcHJvdG90eXBlIHNob3VsZCBiZSB1c2VkIHRvIGNyZWF0ZSBldmVudCBmaWx0ZXJzXG4gKi9cbnZhciBTb2xpZGl0eUV2ZW50ID0gZnVuY3Rpb24gKGpzb24sIGFkZHJlc3MpIHtcbiAgICB0aGlzLl9wYXJhbXMgPSBqc29uLmlucHV0cztcbiAgICB0aGlzLl9uYW1lID0gdXRpbHMudHJhbnNmb3JtVG9GdWxsTmFtZShqc29uKTtcbiAgICB0aGlzLl9hZGRyZXNzID0gYWRkcmVzcztcbiAgICB0aGlzLl9hbm9ueW1vdXMgPSBqc29uLmFub255bW91cztcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZ2V0IGZpbHRlcmVkIHBhcmFtIHR5cGVzXG4gKlxuICogQG1ldGhvZCB0eXBlc1xuICogQHBhcmFtIHtCb29sfSBkZWNpZGUgaWYgcmV0dXJuZWQgdHlwZWQgc2hvdWxkIGJlIGluZGV4ZWRcbiAqIEByZXR1cm4ge0FycmF5fSBhcnJheSBvZiB0eXBlc1xuICovXG5Tb2xpZGl0eUV2ZW50LnByb3RvdHlwZS50eXBlcyA9IGZ1bmN0aW9uIChpbmRleGVkKSB7XG4gICAgcmV0dXJuIHRoaXMuX3BhcmFtcy5maWx0ZXIoZnVuY3Rpb24gKGkpIHtcbiAgICAgICAgcmV0dXJuIGkuaW5kZXhlZCA9PT0gaW5kZXhlZDtcbiAgICB9KS5tYXAoZnVuY3Rpb24gKGkpIHtcbiAgICAgICAgcmV0dXJuIGkudHlwZTtcbiAgICB9KTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZ2V0IGV2ZW50IGRpc3BsYXkgbmFtZVxuICpcbiAqIEBtZXRob2QgZGlzcGxheU5hbWVcbiAqIEByZXR1cm4ge1N0cmluZ30gZXZlbnQgZGlzcGxheSBuYW1lXG4gKi9cblNvbGlkaXR5RXZlbnQucHJvdG90eXBlLmRpc3BsYXlOYW1lID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB1dGlscy5leHRyYWN0RGlzcGxheU5hbWUodGhpcy5fbmFtZSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGdldCBldmVudCB0eXBlIG5hbWVcbiAqXG4gKiBAbWV0aG9kIHR5cGVOYW1lXG4gKiBAcmV0dXJuIHtTdHJpbmd9IGV2ZW50IHR5cGUgbmFtZVxuICovXG5Tb2xpZGl0eUV2ZW50LnByb3RvdHlwZS50eXBlTmFtZSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdXRpbHMuZXh0cmFjdFR5cGVOYW1lKHRoaXMuX25hbWUpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBnZXQgZXZlbnQgc2lnbmF0dXJlXG4gKlxuICogQG1ldGhvZCBzaWduYXR1cmVcbiAqIEByZXR1cm4ge1N0cmluZ30gZXZlbnQgc2lnbmF0dXJlXG4gKi9cblNvbGlkaXR5RXZlbnQucHJvdG90eXBlLnNpZ25hdHVyZSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gc2hhMyh0aGlzLl9uYW1lKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZW5jb2RlIGluZGV4ZWQgcGFyYW1zIGFuZCBvcHRpb25zIHRvIG9uZSBmaW5hbCBvYmplY3RcbiAqIFxuICogQG1ldGhvZCBlbmNvZGVcbiAqIEBwYXJhbSB7T2JqZWN0fSBpbmRleGVkXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9uc1xuICogQHJldHVybiB7T2JqZWN0fSBldmVyeXRoaW5nIGNvbWJpbmVkIHRvZ2V0aGVyIGFuZCBlbmNvZGVkXG4gKi9cblNvbGlkaXR5RXZlbnQucHJvdG90eXBlLmVuY29kZSA9IGZ1bmN0aW9uIChpbmRleGVkLCBvcHRpb25zKSB7XG4gICAgaW5kZXhlZCA9IGluZGV4ZWQgfHwge307XG4gICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgdmFyIHJlc3VsdCA9IHt9O1xuXG4gICAgWydmcm9tQmxvY2snLCAndG9CbG9jayddLmZpbHRlcihmdW5jdGlvbiAoZikge1xuICAgICAgICByZXR1cm4gb3B0aW9uc1tmXSAhPT0gdW5kZWZpbmVkO1xuICAgIH0pLmZvckVhY2goZnVuY3Rpb24gKGYpIHtcbiAgICAgICAgcmVzdWx0W2ZdID0gZm9ybWF0dGVycy5pbnB1dEJsb2NrTnVtYmVyRm9ybWF0dGVyKG9wdGlvbnNbZl0pO1xuICAgIH0pO1xuXG4gICAgcmVzdWx0LnRvcGljcyA9IFtdO1xuXG4gICAgaWYgKCF0aGlzLl9hbm9ueW1vdXMpIHtcbiAgICAgICAgcmVzdWx0LmFkZHJlc3MgPSB0aGlzLl9hZGRyZXNzO1xuICAgICAgICByZXN1bHQudG9waWNzLnB1c2goJzB4JyArIHRoaXMuc2lnbmF0dXJlKCkpO1xuICAgIH1cblxuICAgIHZhciBpbmRleGVkVG9waWNzID0gdGhpcy5fcGFyYW1zLmZpbHRlcihmdW5jdGlvbiAoaSkge1xuICAgICAgICByZXR1cm4gaS5pbmRleGVkID09PSB0cnVlO1xuICAgIH0pLm1hcChmdW5jdGlvbiAoaSkge1xuICAgICAgICB2YXIgdmFsdWUgPSBpbmRleGVkW2kubmFtZV07XG4gICAgICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkIHx8IHZhbHVlID09PSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgaWYgKHV0aWxzLmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICAgICAgICByZXR1cm4gdmFsdWUubWFwKGZ1bmN0aW9uICh2KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICcweCcgKyBjb2Rlci5lbmNvZGVQYXJhbShpLnR5cGUsIHYpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICcweCcgKyBjb2Rlci5lbmNvZGVQYXJhbShpLnR5cGUsIHZhbHVlKTtcbiAgICB9KTtcblxuICAgIHJlc3VsdC50b3BpY3MgPSByZXN1bHQudG9waWNzLmNvbmNhdChpbmRleGVkVG9waWNzKTtcblxuICAgIHJldHVybiByZXN1bHQ7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGRlY29kZSBpbmRleGVkIHBhcmFtcyBhbmQgb3B0aW9uc1xuICpcbiAqIEBtZXRob2QgZGVjb2RlXG4gKiBAcGFyYW0ge09iamVjdH0gZGF0YVxuICogQHJldHVybiB7T2JqZWN0fSByZXN1bHQgb2JqZWN0IHdpdGggZGVjb2RlZCBpbmRleGVkICYmIG5vdCBpbmRleGVkIHBhcmFtc1xuICovXG5Tb2xpZGl0eUV2ZW50LnByb3RvdHlwZS5kZWNvZGUgPSBmdW5jdGlvbiAoZGF0YSkge1xuIFxuICAgIGRhdGEuZGF0YSA9IGRhdGEuZGF0YSB8fCAnJztcbiAgICBkYXRhLnRvcGljcyA9IGRhdGEudG9waWNzIHx8IFtdO1xuXG4gICAgdmFyIGFyZ1RvcGljcyA9IHRoaXMuX2Fub255bW91cyA/IGRhdGEudG9waWNzIDogZGF0YS50b3BpY3Muc2xpY2UoMSk7XG4gICAgdmFyIGluZGV4ZWREYXRhID0gYXJnVG9waWNzLm1hcChmdW5jdGlvbiAodG9waWNzKSB7IHJldHVybiB0b3BpY3Muc2xpY2UoMik7IH0pLmpvaW4oXCJcIik7XG4gICAgdmFyIGluZGV4ZWRQYXJhbXMgPSBjb2Rlci5kZWNvZGVQYXJhbXModGhpcy50eXBlcyh0cnVlKSwgaW5kZXhlZERhdGEpOyBcblxuICAgIHZhciBub3RJbmRleGVkRGF0YSA9IGRhdGEuZGF0YS5zbGljZSgyKTtcbiAgICB2YXIgbm90SW5kZXhlZFBhcmFtcyA9IGNvZGVyLmRlY29kZVBhcmFtcyh0aGlzLnR5cGVzKGZhbHNlKSwgbm90SW5kZXhlZERhdGEpO1xuICAgIFxuICAgIHZhciByZXN1bHQgPSBmb3JtYXR0ZXJzLm91dHB1dExvZ0Zvcm1hdHRlcihkYXRhKTtcbiAgICByZXN1bHQuZXZlbnQgPSB0aGlzLmRpc3BsYXlOYW1lKCk7XG4gICAgcmVzdWx0LmFkZHJlc3MgPSBkYXRhLmFkZHJlc3M7XG5cbiAgICByZXN1bHQuYXJncyA9IHRoaXMuX3BhcmFtcy5yZWR1Y2UoZnVuY3Rpb24gKGFjYywgY3VycmVudCkge1xuICAgICAgICBhY2NbY3VycmVudC5uYW1lXSA9IGN1cnJlbnQuaW5kZXhlZCA/IGluZGV4ZWRQYXJhbXMuc2hpZnQoKSA6IG5vdEluZGV4ZWRQYXJhbXMuc2hpZnQoKTtcbiAgICAgICAgcmV0dXJuIGFjYztcbiAgICB9LCB7fSk7XG5cbiAgICBkZWxldGUgcmVzdWx0LmRhdGE7XG4gICAgZGVsZXRlIHJlc3VsdC50b3BpY3M7XG5cbiAgICByZXR1cm4gcmVzdWx0O1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBjcmVhdGUgbmV3IGZpbHRlciBvYmplY3QgZnJvbSBldmVudFxuICpcbiAqIEBtZXRob2QgZXhlY3V0ZVxuICogQHBhcmFtIHtPYmplY3R9IGluZGV4ZWRcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zXG4gKiBAcmV0dXJuIHtPYmplY3R9IGZpbHRlciBvYmplY3RcbiAqL1xuU29saWRpdHlFdmVudC5wcm90b3R5cGUuZXhlY3V0ZSA9IGZ1bmN0aW9uIChpbmRleGVkLCBvcHRpb25zKSB7XG4gICAgdmFyIG8gPSB0aGlzLmVuY29kZShpbmRleGVkLCBvcHRpb25zKTtcbiAgICB2YXIgZm9ybWF0dGVyID0gdGhpcy5kZWNvZGUuYmluZCh0aGlzKTtcbiAgICByZXR1cm4gd2ViMy5ldGguZmlsdGVyKG8sIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCBmb3JtYXR0ZXIpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBhdHRhY2ggZXZlbnQgdG8gY29udHJhY3Qgb2JqZWN0XG4gKlxuICogQG1ldGhvZCBhdHRhY2hUb0NvbnRyYWN0XG4gKiBAcGFyYW0ge0NvbnRyYWN0fVxuICovXG5Tb2xpZGl0eUV2ZW50LnByb3RvdHlwZS5hdHRhY2hUb0NvbnRyYWN0ID0gZnVuY3Rpb24gKGNvbnRyYWN0KSB7XG4gICAgdmFyIGV4ZWN1dGUgPSB0aGlzLmV4ZWN1dGUuYmluZCh0aGlzKTtcbiAgICB2YXIgZGlzcGxheU5hbWUgPSB0aGlzLmRpc3BsYXlOYW1lKCk7XG4gICAgaWYgKCFjb250cmFjdFtkaXNwbGF5TmFtZV0pIHtcbiAgICAgICAgY29udHJhY3RbZGlzcGxheU5hbWVdID0gZXhlY3V0ZTtcbiAgICB9XG4gICAgY29udHJhY3RbZGlzcGxheU5hbWVdW3RoaXMudHlwZU5hbWUoKV0gPSB0aGlzLmV4ZWN1dGUuYmluZCh0aGlzLCBjb250cmFjdCk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFNvbGlkaXR5RXZlbnQ7XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqIEBmaWxlIGZpbHRlci5qc1xuICogQGF1dGhvcnM6XG4gKiAgIEplZmZyZXkgV2lsY2tlIDxqZWZmQGV0aGRldi5jb20+XG4gKiAgIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogICBNYXJpYW4gT2FuY2VhIDxtYXJpYW5AZXRoZGV2LmNvbT5cbiAqICAgRmFiaWFuIFZvZ2Vsc3RlbGxlciA8ZmFiaWFuQGV0aGRldi5jb20+XG4gKiAgIEdhdiBXb29kIDxnQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE0XG4gKi9cblxudmFyIFJlcXVlc3RNYW5hZ2VyID0gcmVxdWlyZSgnLi9yZXF1ZXN0bWFuYWdlcicpO1xudmFyIGZvcm1hdHRlcnMgPSByZXF1aXJlKCcuL2Zvcm1hdHRlcnMnKTtcbnZhciB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzL3V0aWxzJyk7XG5cbi8qKlxuKiBDb252ZXJ0cyBhIGdpdmVuIHRvcGljIHRvIGEgaGV4IHN0cmluZywgYnV0IGFsc28gYWxsb3dzIG51bGwgdmFsdWVzLlxuKlxuKiBAcGFyYW0ge01peGVkfSB2YWx1ZVxuKiBAcmV0dXJuIHtTdHJpbmd9XG4qL1xudmFyIHRvVG9waWMgPSBmdW5jdGlvbih2YWx1ZSl7XG5cbiAgICBpZih2YWx1ZSA9PT0gbnVsbCB8fCB0eXBlb2YgdmFsdWUgPT09ICd1bmRlZmluZWQnKVxuICAgICAgICByZXR1cm4gbnVsbDtcblxuICAgIHZhbHVlID0gU3RyaW5nKHZhbHVlKTtcblxuICAgIGlmKHZhbHVlLmluZGV4T2YoJzB4JykgPT09IDApXG4gICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICBlbHNlXG4gICAgICAgIHJldHVybiB1dGlscy5mcm9tQXNjaWkodmFsdWUpO1xufTtcblxuLy8vIFRoaXMgbWV0aG9kIHNob3VsZCBiZSBjYWxsZWQgb24gb3B0aW9ucyBvYmplY3QsIHRvIHZlcmlmeSBkZXByZWNhdGVkIHByb3BlcnRpZXMgJiYgbGF6eSBsb2FkIGR5bmFtaWMgb25lc1xuLy8vIEBwYXJhbSBzaG91bGQgYmUgc3RyaW5nIG9yIG9iamVjdFxuLy8vIEByZXR1cm5zIG9wdGlvbnMgc3RyaW5nIG9yIG9iamVjdFxudmFyIGdldE9wdGlvbnMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuXG4gICAgaWYgKHV0aWxzLmlzU3RyaW5nKG9wdGlvbnMpKSB7XG4gICAgICAgIHJldHVybiBvcHRpb25zO1xuICAgIH0gXG5cbiAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgIC8vIG1ha2Ugc3VyZSB0b3BpY3MsIGdldCBjb252ZXJ0ZWQgdG8gaGV4XG4gICAgb3B0aW9ucy50b3BpY3MgPSBvcHRpb25zLnRvcGljcyB8fCBbXTtcbiAgICBvcHRpb25zLnRvcGljcyA9IG9wdGlvbnMudG9waWNzLm1hcChmdW5jdGlvbih0b3BpYyl7XG4gICAgICAgIHJldHVybiAodXRpbHMuaXNBcnJheSh0b3BpYykpID8gdG9waWMubWFwKHRvVG9waWMpIDogdG9Ub3BpYyh0b3BpYyk7XG4gICAgfSk7XG5cbiAgICAvLyBsYXp5IGxvYWRcbiAgICByZXR1cm4ge1xuICAgICAgICB0b3BpY3M6IG9wdGlvbnMudG9waWNzLFxuICAgICAgICB0bzogb3B0aW9ucy50byxcbiAgICAgICAgYWRkcmVzczogb3B0aW9ucy5hZGRyZXNzLFxuICAgICAgICBmcm9tQmxvY2s6IGZvcm1hdHRlcnMuaW5wdXRCbG9ja051bWJlckZvcm1hdHRlcihvcHRpb25zLmZyb21CbG9jayksXG4gICAgICAgIHRvQmxvY2s6IGZvcm1hdHRlcnMuaW5wdXRCbG9ja051bWJlckZvcm1hdHRlcihvcHRpb25zLnRvQmxvY2spIFxuICAgIH07IFxufTtcblxudmFyIEZpbHRlciA9IGZ1bmN0aW9uIChvcHRpb25zLCBtZXRob2RzLCBmb3JtYXR0ZXIpIHtcbiAgICB2YXIgaW1wbGVtZW50YXRpb24gPSB7fTtcbiAgICBtZXRob2RzLmZvckVhY2goZnVuY3Rpb24gKG1ldGhvZCkge1xuICAgICAgICBtZXRob2QuYXR0YWNoVG9PYmplY3QoaW1wbGVtZW50YXRpb24pO1xuICAgIH0pO1xuICAgIHRoaXMub3B0aW9ucyA9IGdldE9wdGlvbnMob3B0aW9ucyk7XG4gICAgdGhpcy5pbXBsZW1lbnRhdGlvbiA9IGltcGxlbWVudGF0aW9uO1xuICAgIHRoaXMuY2FsbGJhY2tzID0gW107XG4gICAgdGhpcy5mb3JtYXR0ZXIgPSBmb3JtYXR0ZXI7XG4gICAgdGhpcy5maWx0ZXJJZCA9IHRoaXMuaW1wbGVtZW50YXRpb24ubmV3RmlsdGVyKHRoaXMub3B0aW9ucyk7XG59O1xuXG5GaWx0ZXIucHJvdG90eXBlLndhdGNoID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gICAgdGhpcy5jYWxsYmFja3MucHVzaChjYWxsYmFjayk7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgdmFyIG9uTWVzc2FnZSA9IGZ1bmN0aW9uIChlcnJvciwgbWVzc2FnZXMpIHtcbiAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICByZXR1cm4gc2VsZi5jYWxsYmFja3MuZm9yRWFjaChmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICBjYWxsYmFjayhlcnJvcik7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIG1lc3NhZ2VzLmZvckVhY2goZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgICAgIG1lc3NhZ2UgPSBzZWxmLmZvcm1hdHRlciA/IHNlbGYuZm9ybWF0dGVyKG1lc3NhZ2UpIDogbWVzc2FnZTtcbiAgICAgICAgICAgIHNlbGYuY2FsbGJhY2tzLmZvckVhY2goZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwgbWVzc2FnZSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIC8vIGNhbGwgZ2V0RmlsdGVyTG9ncyBvbiBzdGFydFxuICAgIGlmICghdXRpbHMuaXNTdHJpbmcodGhpcy5vcHRpb25zKSkge1xuICAgICAgICB0aGlzLmdldChmdW5jdGlvbiAoZXJyLCBtZXNzYWdlcykge1xuICAgICAgICAgICAgLy8gZG9uJ3Qgc2VuZCBhbGwgdGhlIHJlc3BvbnNlcyB0byBhbGwgdGhlIHdhdGNoZXMgYWdhaW4uLi4ganVzdCB0byB0aGlzIG9uZVxuICAgICAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKGVycik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG1lc3NhZ2VzLmZvckVhY2goZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgICAgICAgICBjYWxsYmFjayhudWxsLCBtZXNzYWdlKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBSZXF1ZXN0TWFuYWdlci5nZXRJbnN0YW5jZSgpLnN0YXJ0UG9sbGluZyh7XG4gICAgICAgIG1ldGhvZDogdGhpcy5pbXBsZW1lbnRhdGlvbi5wb2xsLmNhbGwsXG4gICAgICAgIHBhcmFtczogW3RoaXMuZmlsdGVySWRdLFxuICAgIH0sIHRoaXMuZmlsdGVySWQsIG9uTWVzc2FnZSwgdGhpcy5zdG9wV2F0Y2hpbmcuYmluZCh0aGlzKSk7XG59O1xuXG5GaWx0ZXIucHJvdG90eXBlLnN0b3BXYXRjaGluZyA9IGZ1bmN0aW9uICgpIHtcbiAgICBSZXF1ZXN0TWFuYWdlci5nZXRJbnN0YW5jZSgpLnN0b3BQb2xsaW5nKHRoaXMuZmlsdGVySWQpO1xuICAgIHRoaXMuaW1wbGVtZW50YXRpb24udW5pbnN0YWxsRmlsdGVyKHRoaXMuZmlsdGVySWQpO1xuICAgIHRoaXMuY2FsbGJhY2tzID0gW107XG59O1xuXG5GaWx0ZXIucHJvdG90eXBlLmdldCA9IGZ1bmN0aW9uIChjYWxsYmFjaykge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICBpZiAodXRpbHMuaXNGdW5jdGlvbihjYWxsYmFjaykpIHtcbiAgICAgICAgdGhpcy5pbXBsZW1lbnRhdGlvbi5nZXRMb2dzKHRoaXMuZmlsdGVySWQsIGZ1bmN0aW9uKGVyciwgcmVzKXtcbiAgICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgICAgICBjYWxsYmFjayhlcnIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjYWxsYmFjayhudWxsLCByZXMubWFwKGZ1bmN0aW9uIChsb2cpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHNlbGYuZm9ybWF0dGVyID8gc2VsZi5mb3JtYXR0ZXIobG9nKSA6IGxvZztcbiAgICAgICAgICAgICAgICB9KSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBsb2dzID0gdGhpcy5pbXBsZW1lbnRhdGlvbi5nZXRMb2dzKHRoaXMuZmlsdGVySWQpO1xuICAgICAgICByZXR1cm4gbG9ncy5tYXAoZnVuY3Rpb24gKGxvZykge1xuICAgICAgICAgICAgcmV0dXJuIHNlbGYuZm9ybWF0dGVyID8gc2VsZi5mb3JtYXR0ZXIobG9nKSA6IGxvZztcbiAgICAgICAgfSk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBGaWx0ZXI7XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqIFxuICogQGZpbGUgZm9ybWF0dGVycy5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBhdXRob3IgRmFiaWFuIFZvZ2Vsc3RlbGxlciA8ZmFiaWFuQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE1XG4gKi9cblxudmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMvdXRpbHMnKTtcbnZhciBjb25maWcgPSByZXF1aXJlKCcuLi91dGlscy9jb25maWcnKTtcblxuLyoqXG4gKiBTaG91bGQgdGhlIGZvcm1hdCBvdXRwdXQgdG8gYSBiaWcgbnVtYmVyXG4gKlxuICogQG1ldGhvZCBvdXRwdXRCaWdOdW1iZXJGb3JtYXR0ZXJcbiAqIEBwYXJhbSB7U3RyaW5nfE51bWJlcnxCaWdOdW1iZXJ9XG4gKiBAcmV0dXJucyB7QmlnTnVtYmVyfSBvYmplY3RcbiAqL1xudmFyIG91dHB1dEJpZ051bWJlckZvcm1hdHRlciA9IGZ1bmN0aW9uIChudW1iZXIpIHtcbiAgICByZXR1cm4gdXRpbHMudG9CaWdOdW1iZXIobnVtYmVyKTtcbn07XG5cbnZhciBpc1ByZWRlZmluZWRCbG9ja051bWJlciA9IGZ1bmN0aW9uIChibG9ja051bWJlcikge1xuICAgIHJldHVybiBibG9ja051bWJlciA9PT0gJ2xhdGVzdCcgfHwgYmxvY2tOdW1iZXIgPT09ICdwZW5kaW5nJyB8fCBibG9ja051bWJlciA9PT0gJ2VhcmxpZXN0Jztcbn07XG5cbnZhciBpbnB1dERlZmF1bHRCbG9ja051bWJlckZvcm1hdHRlciA9IGZ1bmN0aW9uIChibG9ja051bWJlcikge1xuICAgIGlmIChibG9ja051bWJlciA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiBjb25maWcuZGVmYXVsdEJsb2NrO1xuICAgIH1cbiAgICByZXR1cm4gaW5wdXRCbG9ja051bWJlckZvcm1hdHRlcihibG9ja051bWJlcik7XG59O1xuXG52YXIgaW5wdXRCbG9ja051bWJlckZvcm1hdHRlciA9IGZ1bmN0aW9uIChibG9ja051bWJlcikge1xuICAgIGlmIChibG9ja051bWJlciA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfSBlbHNlIGlmIChpc1ByZWRlZmluZWRCbG9ja051bWJlcihibG9ja051bWJlcikpIHtcbiAgICAgICAgcmV0dXJuIGJsb2NrTnVtYmVyO1xuICAgIH1cbiAgICByZXR1cm4gdXRpbHMudG9IZXgoYmxvY2tOdW1iZXIpO1xufTtcblxuLyoqXG4gKiBGb3JtYXRzIHRoZSBpbnB1dCBvZiBhIHRyYW5zYWN0aW9uIGFuZCBjb252ZXJ0cyBhbGwgdmFsdWVzIHRvIEhFWFxuICpcbiAqIEBtZXRob2QgaW5wdXRUcmFuc2FjdGlvbkZvcm1hdHRlclxuICogQHBhcmFtIHtPYmplY3R9IHRyYW5zYWN0aW9uIG9wdGlvbnNcbiAqIEByZXR1cm5zIG9iamVjdFxuKi9cbnZhciBpbnB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyID0gZnVuY3Rpb24gKG9wdGlvbnMpe1xuXG4gICAgb3B0aW9ucy5mcm9tID0gb3B0aW9ucy5mcm9tIHx8IGNvbmZpZy5kZWZhdWx0QWNjb3VudDtcblxuICAgIC8vIG1ha2UgY29kZSAtPiBkYXRhXG4gICAgaWYgKG9wdGlvbnMuY29kZSkge1xuICAgICAgICBvcHRpb25zLmRhdGEgPSBvcHRpb25zLmNvZGU7XG4gICAgICAgIGRlbGV0ZSBvcHRpb25zLmNvZGU7XG4gICAgfVxuXG4gICAgWydnYXNQcmljZScsICdnYXMnLCAndmFsdWUnLCAnbm9uY2UnXS5maWx0ZXIoZnVuY3Rpb24gKGtleSkge1xuICAgICAgICByZXR1cm4gb3B0aW9uc1trZXldICE9PSB1bmRlZmluZWQ7XG4gICAgfSkuZm9yRWFjaChmdW5jdGlvbihrZXkpe1xuICAgICAgICBvcHRpb25zW2tleV0gPSB1dGlscy5mcm9tRGVjaW1hbChvcHRpb25zW2tleV0pO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIG9wdGlvbnM7IFxufTtcblxuLyoqXG4gKiBGb3JtYXRzIHRoZSBvdXRwdXQgb2YgYSB0cmFuc2FjdGlvbiB0byBpdHMgcHJvcGVyIHZhbHVlc1xuICogXG4gKiBAbWV0aG9kIG91dHB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyXG4gKiBAcGFyYW0ge09iamVjdH0gdHJhbnNhY3Rpb25cbiAqIEByZXR1cm5zIHtPYmplY3R9IHRyYW5zYWN0aW9uXG4qL1xudmFyIG91dHB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyID0gZnVuY3Rpb24gKHR4KXtcbiAgICB0eC5ibG9ja051bWJlciA9IHV0aWxzLnRvRGVjaW1hbCh0eC5ibG9ja051bWJlcik7XG4gICAgdHgudHJhbnNhY3Rpb25JbmRleCA9IHV0aWxzLnRvRGVjaW1hbCh0eC50cmFuc2FjdGlvbkluZGV4KTtcbiAgICB0eC5ub25jZSA9IHV0aWxzLnRvRGVjaW1hbCh0eC5ub25jZSk7XG4gICAgdHguZ2FzID0gdXRpbHMudG9EZWNpbWFsKHR4Lmdhcyk7XG4gICAgdHguZ2FzUHJpY2UgPSB1dGlscy50b0JpZ051bWJlcih0eC5nYXNQcmljZSk7XG4gICAgdHgudmFsdWUgPSB1dGlscy50b0JpZ051bWJlcih0eC52YWx1ZSk7XG4gICAgcmV0dXJuIHR4O1xufTtcblxuLyoqXG4gKiBGb3JtYXRzIHRoZSBvdXRwdXQgb2YgYSBibG9jayB0byBpdHMgcHJvcGVyIHZhbHVlc1xuICpcbiAqIEBtZXRob2Qgb3V0cHV0QmxvY2tGb3JtYXR0ZXJcbiAqIEBwYXJhbSB7T2JqZWN0fSBibG9jayBvYmplY3QgXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBibG9jayBvYmplY3RcbiovXG52YXIgb3V0cHV0QmxvY2tGb3JtYXR0ZXIgPSBmdW5jdGlvbihibG9jaykge1xuXG4gICAgLy8gdHJhbnNmb3JtIHRvIG51bWJlclxuICAgIGJsb2NrLmdhc0xpbWl0ID0gdXRpbHMudG9EZWNpbWFsKGJsb2NrLmdhc0xpbWl0KTtcbiAgICBibG9jay5nYXNVc2VkID0gdXRpbHMudG9EZWNpbWFsKGJsb2NrLmdhc1VzZWQpO1xuICAgIGJsb2NrLnNpemUgPSB1dGlscy50b0RlY2ltYWwoYmxvY2suc2l6ZSk7XG4gICAgYmxvY2sudGltZXN0YW1wID0gdXRpbHMudG9EZWNpbWFsKGJsb2NrLnRpbWVzdGFtcCk7XG4gICAgYmxvY2subnVtYmVyID0gdXRpbHMudG9EZWNpbWFsKGJsb2NrLm51bWJlcik7XG5cbiAgICBibG9jay5kaWZmaWN1bHR5ID0gdXRpbHMudG9CaWdOdW1iZXIoYmxvY2suZGlmZmljdWx0eSk7XG4gICAgYmxvY2sudG90YWxEaWZmaWN1bHR5ID0gdXRpbHMudG9CaWdOdW1iZXIoYmxvY2sudG90YWxEaWZmaWN1bHR5KTtcblxuICAgIGlmICh1dGlscy5pc0FycmF5KGJsb2NrLnRyYW5zYWN0aW9ucykpIHtcbiAgICAgICAgYmxvY2sudHJhbnNhY3Rpb25zLmZvckVhY2goZnVuY3Rpb24oaXRlbSl7XG4gICAgICAgICAgICBpZighdXRpbHMuaXNTdHJpbmcoaXRlbSkpXG4gICAgICAgICAgICAgICAgcmV0dXJuIG91dHB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyKGl0ZW0pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gYmxvY2s7XG59O1xuXG4vKipcbiAqIEZvcm1hdHMgdGhlIG91dHB1dCBvZiBhIGxvZ1xuICogXG4gKiBAbWV0aG9kIG91dHB1dExvZ0Zvcm1hdHRlclxuICogQHBhcmFtIHtPYmplY3R9IGxvZyBvYmplY3RcbiAqIEByZXR1cm5zIHtPYmplY3R9IGxvZ1xuKi9cbnZhciBvdXRwdXRMb2dGb3JtYXR0ZXIgPSBmdW5jdGlvbihsb2cpIHtcbiAgICBpZiAobG9nID09PSBudWxsKSB7IC8vICdwZW5kaW5nJyAmJiAnbGF0ZXN0JyBmaWx0ZXJzIGFyZSBudWxsc1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBsb2cuYmxvY2tOdW1iZXIgPSB1dGlscy50b0RlY2ltYWwobG9nLmJsb2NrTnVtYmVyKTtcbiAgICBsb2cudHJhbnNhY3Rpb25JbmRleCA9IHV0aWxzLnRvRGVjaW1hbChsb2cudHJhbnNhY3Rpb25JbmRleCk7XG4gICAgbG9nLmxvZ0luZGV4ID0gdXRpbHMudG9EZWNpbWFsKGxvZy5sb2dJbmRleCk7XG5cbiAgICByZXR1cm4gbG9nO1xufTtcblxuLyoqXG4gKiBGb3JtYXRzIHRoZSBpbnB1dCBvZiBhIHdoaXNwZXIgcG9zdCBhbmQgY29udmVydHMgYWxsIHZhbHVlcyB0byBIRVhcbiAqXG4gKiBAbWV0aG9kIGlucHV0UG9zdEZvcm1hdHRlclxuICogQHBhcmFtIHtPYmplY3R9IHRyYW5zYWN0aW9uIG9iamVjdFxuICogQHJldHVybnMge09iamVjdH1cbiovXG52YXIgaW5wdXRQb3N0Rm9ybWF0dGVyID0gZnVuY3Rpb24ocG9zdCkge1xuXG4gICAgcG9zdC5wYXlsb2FkID0gdXRpbHMudG9IZXgocG9zdC5wYXlsb2FkKTtcbiAgICBwb3N0LnR0bCA9IHV0aWxzLmZyb21EZWNpbWFsKHBvc3QudHRsKTtcbiAgICBwb3N0LndvcmtUb1Byb3ZlID0gdXRpbHMuZnJvbURlY2ltYWwocG9zdC53b3JrVG9Qcm92ZSk7XG4gICAgcG9zdC5wcmlvcml0eSA9IHV0aWxzLmZyb21EZWNpbWFsKHBvc3QucHJpb3JpdHkpO1xuXG4gICAgLy8gZmFsbGJhY2tcbiAgICBpZiAoIXV0aWxzLmlzQXJyYXkocG9zdC50b3BpY3MpKSB7XG4gICAgICAgIHBvc3QudG9waWNzID0gcG9zdC50b3BpY3MgPyBbcG9zdC50b3BpY3NdIDogW107XG4gICAgfVxuXG4gICAgLy8gZm9ybWF0IHRoZSBmb2xsb3dpbmcgb3B0aW9uc1xuICAgIHBvc3QudG9waWNzID0gcG9zdC50b3BpY3MubWFwKGZ1bmN0aW9uKHRvcGljKXtcbiAgICAgICAgcmV0dXJuIHV0aWxzLmZyb21Bc2NpaSh0b3BpYyk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gcG9zdDsgXG59O1xuXG4vKipcbiAqIEZvcm1hdHMgdGhlIG91dHB1dCBvZiBhIHJlY2VpdmVkIHBvc3QgbWVzc2FnZVxuICpcbiAqIEBtZXRob2Qgb3V0cHV0UG9zdEZvcm1hdHRlclxuICogQHBhcmFtIHtPYmplY3R9XG4gKiBAcmV0dXJucyB7T2JqZWN0fVxuICovXG52YXIgb3V0cHV0UG9zdEZvcm1hdHRlciA9IGZ1bmN0aW9uKHBvc3Qpe1xuXG4gICAgcG9zdC5leHBpcnkgPSB1dGlscy50b0RlY2ltYWwocG9zdC5leHBpcnkpO1xuICAgIHBvc3Quc2VudCA9IHV0aWxzLnRvRGVjaW1hbChwb3N0LnNlbnQpO1xuICAgIHBvc3QudHRsID0gdXRpbHMudG9EZWNpbWFsKHBvc3QudHRsKTtcbiAgICBwb3N0LndvcmtQcm92ZWQgPSB1dGlscy50b0RlY2ltYWwocG9zdC53b3JrUHJvdmVkKTtcbiAgICBwb3N0LnBheWxvYWRSYXcgPSBwb3N0LnBheWxvYWQ7XG4gICAgcG9zdC5wYXlsb2FkID0gdXRpbHMudG9Bc2NpaShwb3N0LnBheWxvYWQpO1xuXG4gICAgaWYgKHV0aWxzLmlzSnNvbihwb3N0LnBheWxvYWQpKSB7XG4gICAgICAgIHBvc3QucGF5bG9hZCA9IEpTT04ucGFyc2UocG9zdC5wYXlsb2FkKTtcbiAgICB9XG5cbiAgICAvLyBmb3JtYXQgdGhlIGZvbGxvd2luZyBvcHRpb25zXG4gICAgaWYgKCFwb3N0LnRvcGljcykge1xuICAgICAgICBwb3N0LnRvcGljcyA9IFtdO1xuICAgIH1cbiAgICBwb3N0LnRvcGljcyA9IHBvc3QudG9waWNzLm1hcChmdW5jdGlvbih0b3BpYyl7XG4gICAgICAgIHJldHVybiB1dGlscy50b0FzY2lpKHRvcGljKTtcbiAgICB9KTtcblxuICAgIHJldHVybiBwb3N0O1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgaW5wdXREZWZhdWx0QmxvY2tOdW1iZXJGb3JtYXR0ZXI6IGlucHV0RGVmYXVsdEJsb2NrTnVtYmVyRm9ybWF0dGVyLFxuICAgIGlucHV0QmxvY2tOdW1iZXJGb3JtYXR0ZXI6IGlucHV0QmxvY2tOdW1iZXJGb3JtYXR0ZXIsXG4gICAgaW5wdXRUcmFuc2FjdGlvbkZvcm1hdHRlcjogaW5wdXRUcmFuc2FjdGlvbkZvcm1hdHRlcixcbiAgICBpbnB1dFBvc3RGb3JtYXR0ZXI6IGlucHV0UG9zdEZvcm1hdHRlcixcbiAgICBvdXRwdXRCaWdOdW1iZXJGb3JtYXR0ZXI6IG91dHB1dEJpZ051bWJlckZvcm1hdHRlcixcbiAgICBvdXRwdXRUcmFuc2FjdGlvbkZvcm1hdHRlcjogb3V0cHV0VHJhbnNhY3Rpb25Gb3JtYXR0ZXIsXG4gICAgb3V0cHV0QmxvY2tGb3JtYXR0ZXI6IG91dHB1dEJsb2NrRm9ybWF0dGVyLFxuICAgIG91dHB1dExvZ0Zvcm1hdHRlcjogb3V0cHV0TG9nRm9ybWF0dGVyLFxuICAgIG91dHB1dFBvc3RGb3JtYXR0ZXI6IG91dHB1dFBvc3RGb3JtYXR0ZXJcbn07XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqXG4gKiBAZmlsZSBmdW5jdGlvbi5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgd2ViMyA9IHJlcXVpcmUoJy4uL3dlYjMnKTtcbnZhciBjb2RlciA9IHJlcXVpcmUoJy4uL3NvbGlkaXR5L2NvZGVyJyk7XG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy91dGlscycpO1xudmFyIHNoYTMgPSByZXF1aXJlKCcuLi91dGlscy9zaGEzJyk7XG5cbi8qKlxuICogVGhpcyBwcm90b3R5cGUgc2hvdWxkIGJlIHVzZWQgdG8gY2FsbC9zZW5kVHJhbnNhY3Rpb24gdG8gc29saWRpdHkgZnVuY3Rpb25zXG4gKi9cbnZhciBTb2xpZGl0eUZ1bmN0aW9uID0gZnVuY3Rpb24gKGpzb24sIGFkZHJlc3MpIHtcbiAgICB0aGlzLl9pbnB1dFR5cGVzID0ganNvbi5pbnB1dHMubWFwKGZ1bmN0aW9uIChpKSB7XG4gICAgICAgIHJldHVybiBpLnR5cGU7XG4gICAgfSk7XG4gICAgdGhpcy5fb3V0cHV0VHlwZXMgPSBqc29uLm91dHB1dHMubWFwKGZ1bmN0aW9uIChpKSB7XG4gICAgICAgIHJldHVybiBpLnR5cGU7XG4gICAgfSk7XG4gICAgdGhpcy5fY29uc3RhbnQgPSBqc29uLmNvbnN0YW50O1xuICAgIHRoaXMuX25hbWUgPSB1dGlscy50cmFuc2Zvcm1Ub0Z1bGxOYW1lKGpzb24pO1xuICAgIHRoaXMuX2FkZHJlc3MgPSBhZGRyZXNzO1xufTtcblxuU29saWRpdHlGdW5jdGlvbi5wcm90b3R5cGUuZXh0cmFjdENhbGxiYWNrID0gZnVuY3Rpb24gKGFyZ3MpIHtcbiAgICBpZiAodXRpbHMuaXNGdW5jdGlvbihhcmdzW2FyZ3MubGVuZ3RoIC0gMV0pKSB7XG4gICAgICAgIHJldHVybiBhcmdzLnBvcCgpOyAvLyBtb2RpZnkgdGhlIGFyZ3MgYXJyYXkhXG4gICAgfVxufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBjcmVhdGUgcGF5bG9hZCBmcm9tIGFyZ3VtZW50c1xuICpcbiAqIEBtZXRob2QgdG9QYXlsb2FkXG4gKiBAcGFyYW0ge0FycmF5fSBzb2xpZGl0eSBmdW5jdGlvbiBwYXJhbXNcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25hbCBwYXlsb2FkIG9wdGlvbnNcbiAqL1xuU29saWRpdHlGdW5jdGlvbi5wcm90b3R5cGUudG9QYXlsb2FkID0gZnVuY3Rpb24gKGFyZ3MpIHtcbiAgICB2YXIgb3B0aW9ucyA9IHt9O1xuICAgIGlmIChhcmdzLmxlbmd0aCA+IHRoaXMuX2lucHV0VHlwZXMubGVuZ3RoICYmIHV0aWxzLmlzT2JqZWN0KGFyZ3NbYXJncy5sZW5ndGggLTFdKSkge1xuICAgICAgICBvcHRpb25zID0gYXJnc1thcmdzLmxlbmd0aCAtIDFdO1xuICAgIH1cbiAgICBvcHRpb25zLnRvID0gdGhpcy5fYWRkcmVzcztcbiAgICBvcHRpb25zLmRhdGEgPSAnMHgnICsgdGhpcy5zaWduYXR1cmUoKSArIGNvZGVyLmVuY29kZVBhcmFtcyh0aGlzLl9pbnB1dFR5cGVzLCBhcmdzKTtcbiAgICByZXR1cm4gb3B0aW9ucztcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZ2V0IGZ1bmN0aW9uIHNpZ25hdHVyZVxuICpcbiAqIEBtZXRob2Qgc2lnbmF0dXJlXG4gKiBAcmV0dXJuIHtTdHJpbmd9IGZ1bmN0aW9uIHNpZ25hdHVyZVxuICovXG5Tb2xpZGl0eUZ1bmN0aW9uLnByb3RvdHlwZS5zaWduYXR1cmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHNoYTModGhpcy5fbmFtZSkuc2xpY2UoMCwgOCk7XG59O1xuXG5cblNvbGlkaXR5RnVuY3Rpb24ucHJvdG90eXBlLnVucGFja091dHB1dCA9IGZ1bmN0aW9uIChvdXRwdXQpIHtcbiAgICBpZiAoIW91dHB1dCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgb3V0cHV0ID0gb3V0cHV0Lmxlbmd0aCA+PSAyID8gb3V0cHV0LnNsaWNlKDIpIDogb3V0cHV0O1xuICAgIHZhciByZXN1bHQgPSBjb2Rlci5kZWNvZGVQYXJhbXModGhpcy5fb3V0cHV0VHlwZXMsIG91dHB1dCk7XG4gICAgcmV0dXJuIHJlc3VsdC5sZW5ndGggPT09IDEgPyByZXN1bHRbMF0gOiByZXN1bHQ7XG59O1xuXG4vKipcbiAqIENhbGxzIGEgY29udHJhY3QgZnVuY3Rpb24uXG4gKlxuICogQG1ldGhvZCBjYWxsXG4gKiBAcGFyYW0gey4uLk9iamVjdH0gQ29udHJhY3QgZnVuY3Rpb24gYXJndW1lbnRzXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBJZiB0aGUgbGFzdCBhcmd1bWVudCBpcyBhIGZ1bmN0aW9uLCB0aGUgY29udHJhY3QgZnVuY3Rpb25cbiAqICAgY2FsbCB3aWxsIGJlIGFzeW5jaHJvbm91cywgYW5kIHRoZSBjYWxsYmFjayB3aWxsIGJlIHBhc3NlZCB0aGVcbiAqICAgZXJyb3IgYW5kIHJlc3VsdC5cbiAqIEByZXR1cm4ge1N0cmluZ30gb3V0cHV0IGJ5dGVzXG4gKi9cblNvbGlkaXR5RnVuY3Rpb24ucHJvdG90eXBlLmNhbGwgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpLmZpbHRlcihmdW5jdGlvbiAoYSkge3JldHVybiBhICE9PSB1bmRlZmluZWQ7IH0pO1xuICAgIHZhciBjYWxsYmFjayA9IHRoaXMuZXh0cmFjdENhbGxiYWNrKGFyZ3MpO1xuICAgIHZhciBwYXlsb2FkID0gdGhpcy50b1BheWxvYWQoYXJncyk7XG5cbiAgICBpZiAoIWNhbGxiYWNrKSB7XG4gICAgICAgIHZhciBvdXRwdXQgPSB3ZWIzLmV0aC5jYWxsKHBheWxvYWQpO1xuICAgICAgICByZXR1cm4gdGhpcy51bnBhY2tPdXRwdXQob3V0cHV0KTtcbiAgICB9IFxuICAgICAgICBcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgd2ViMy5ldGguY2FsbChwYXlsb2FkLCBmdW5jdGlvbiAoZXJyb3IsIG91dHB1dCkge1xuICAgICAgICBjYWxsYmFjayhlcnJvciwgc2VsZi51bnBhY2tPdXRwdXQob3V0cHV0KSk7XG4gICAgfSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIHNlbmRUcmFuc2FjdGlvbiB0byBzb2xpZGl0eSBmdW5jdGlvblxuICpcbiAqIEBtZXRob2Qgc2VuZFRyYW5zYWN0aW9uXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9uc1xuICovXG5Tb2xpZGl0eUZ1bmN0aW9uLnByb3RvdHlwZS5zZW5kVHJhbnNhY3Rpb24gPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpLmZpbHRlcihmdW5jdGlvbiAoYSkge3JldHVybiBhICE9PSB1bmRlZmluZWQ7IH0pO1xuICAgIHZhciBjYWxsYmFjayA9IHRoaXMuZXh0cmFjdENhbGxiYWNrKGFyZ3MpO1xuICAgIHZhciBwYXlsb2FkID0gdGhpcy50b1BheWxvYWQoYXJncyk7XG5cbiAgICBpZiAoIWNhbGxiYWNrKSB7XG4gICAgICAgIHJldHVybiB3ZWIzLmV0aC5zZW5kVHJhbnNhY3Rpb24ocGF5bG9hZCk7XG4gICAgfVxuXG4gICAgd2ViMy5ldGguc2VuZFRyYW5zYWN0aW9uKHBheWxvYWQsIGNhbGxiYWNrKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZXN0aW1hdGVHYXMgb2Ygc29saWRpdHkgZnVuY3Rpb25cbiAqXG4gKiBAbWV0aG9kIGVzdGltYXRlR2FzXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9uc1xuICovXG5Tb2xpZGl0eUZ1bmN0aW9uLnByb3RvdHlwZS5lc3RpbWF0ZUdhcyA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cyk7XG4gICAgdmFyIGNhbGxiYWNrID0gdGhpcy5leHRyYWN0Q2FsbGJhY2soYXJncyk7XG4gICAgdmFyIHBheWxvYWQgPSB0aGlzLnRvUGF5bG9hZChhcmdzKTtcblxuICAgIGlmICghY2FsbGJhY2spIHtcbiAgICAgICAgcmV0dXJuIHdlYjMuZXRoLmVzdGltYXRlR2FzKHBheWxvYWQpO1xuICAgIH1cblxuICAgIHdlYjMuZXRoLmVzdGltYXRlR2FzKHBheWxvYWQsIGNhbGxiYWNrKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZ2V0IGZ1bmN0aW9uIGRpc3BsYXkgbmFtZVxuICpcbiAqIEBtZXRob2QgZGlzcGxheU5hbWVcbiAqIEByZXR1cm4ge1N0cmluZ30gZGlzcGxheSBuYW1lIG9mIHRoZSBmdW5jdGlvblxuICovXG5Tb2xpZGl0eUZ1bmN0aW9uLnByb3RvdHlwZS5kaXNwbGF5TmFtZSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdXRpbHMuZXh0cmFjdERpc3BsYXlOYW1lKHRoaXMuX25hbWUpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBnZXQgZnVuY3Rpb24gdHlwZSBuYW1lXG4gKlxuICogQG1ldGhvZCB0eXBlTmFtZVxuICogQHJldHVybiB7U3RyaW5nfSB0eXBlIG5hbWUgb2YgdGhlIGZ1bmN0aW9uXG4gKi9cblNvbGlkaXR5RnVuY3Rpb24ucHJvdG90eXBlLnR5cGVOYW1lID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB1dGlscy5leHRyYWN0VHlwZU5hbWUodGhpcy5fbmFtZSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZ2V0IHJwYyByZXF1ZXN0cyBmcm9tIHNvbGlkaXR5IGZ1bmN0aW9uXG4gKlxuICogQG1ldGhvZCByZXF1ZXN0XG4gKiBAcmV0dXJucyB7T2JqZWN0fVxuICovXG5Tb2xpZGl0eUZ1bmN0aW9uLnByb3RvdHlwZS5yZXF1ZXN0ID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKTtcbiAgICB2YXIgY2FsbGJhY2sgPSB0aGlzLmV4dHJhY3RDYWxsYmFjayhhcmdzKTtcbiAgICB2YXIgcGF5bG9hZCA9IHRoaXMudG9QYXlsb2FkKGFyZ3MpO1xuICAgIHZhciBmb3JtYXQgPSB0aGlzLnVucGFja091dHB1dC5iaW5kKHRoaXMpO1xuICAgIFxuICAgIHJldHVybiB7XG4gICAgICAgIGNhbGxiYWNrOiBjYWxsYmFjayxcbiAgICAgICAgcGF5bG9hZDogcGF5bG9hZCwgXG4gICAgICAgIGZvcm1hdDogZm9ybWF0XG4gICAgfTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBleGVjdXRlIGZ1bmN0aW9uXG4gKlxuICogQG1ldGhvZCBleGVjdXRlXG4gKi9cblNvbGlkaXR5RnVuY3Rpb24ucHJvdG90eXBlLmV4ZWN1dGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIHRyYW5zYWN0aW9uID0gIXRoaXMuX2NvbnN0YW50O1xuXG4gICAgLy8gc2VuZCB0cmFuc2FjdGlvblxuICAgIGlmICh0cmFuc2FjdGlvbikge1xuICAgICAgICByZXR1cm4gdGhpcy5zZW5kVHJhbnNhY3Rpb24uYXBwbHkodGhpcywgQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKSk7XG4gICAgfVxuXG4gICAgLy8gY2FsbFxuICAgIHJldHVybiB0aGlzLmNhbGwuYXBwbHkodGhpcywgQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gYXR0YWNoIGZ1bmN0aW9uIHRvIGNvbnRyYWN0XG4gKlxuICogQG1ldGhvZCBhdHRhY2hUb0NvbnRyYWN0XG4gKiBAcGFyYW0ge0NvbnRyYWN0fVxuICovXG5Tb2xpZGl0eUZ1bmN0aW9uLnByb3RvdHlwZS5hdHRhY2hUb0NvbnRyYWN0ID0gZnVuY3Rpb24gKGNvbnRyYWN0KSB7XG4gICAgdmFyIGV4ZWN1dGUgPSB0aGlzLmV4ZWN1dGUuYmluZCh0aGlzKTtcbiAgICBleGVjdXRlLnJlcXVlc3QgPSB0aGlzLnJlcXVlc3QuYmluZCh0aGlzKTtcbiAgICBleGVjdXRlLmNhbGwgPSB0aGlzLmNhbGwuYmluZCh0aGlzKTtcbiAgICBleGVjdXRlLnNlbmRUcmFuc2FjdGlvbiA9IHRoaXMuc2VuZFRyYW5zYWN0aW9uLmJpbmQodGhpcyk7XG4gICAgZXhlY3V0ZS5lc3RpbWF0ZUdhcyA9IHRoaXMuZXN0aW1hdGVHYXMuYmluZCh0aGlzKTtcbiAgICB2YXIgZGlzcGxheU5hbWUgPSB0aGlzLmRpc3BsYXlOYW1lKCk7XG4gICAgaWYgKCFjb250cmFjdFtkaXNwbGF5TmFtZV0pIHtcbiAgICAgICAgY29udHJhY3RbZGlzcGxheU5hbWVdID0gZXhlY3V0ZTtcbiAgICB9XG4gICAgY29udHJhY3RbZGlzcGxheU5hbWVdW3RoaXMudHlwZU5hbWUoKV0gPSBleGVjdXRlOyAvLyBjaXJjdWxhciEhISFcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gU29saWRpdHlGdW5jdGlvbjtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogQGZpbGUgaHR0cHByb3ZpZGVyLmpzXG4gKiBAYXV0aG9yczpcbiAqICAgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiAgIE1hcmlhbiBPYW5jZWEgPG1hcmlhbkBldGhkZXYuY29tPlxuICogICBGYWJpYW4gVm9nZWxzdGVsbGVyIDxmYWJpYW5AZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTRcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFhNTEh0dHBSZXF1ZXN0ID0gcmVxdWlyZSgneG1saHR0cHJlcXVlc3QnKS5YTUxIdHRwUmVxdWVzdDsgLy8ganNoaW50IGlnbm9yZTpsaW5lXG52YXIgZXJyb3JzID0gcmVxdWlyZSgnLi9lcnJvcnMnKTtcblxudmFyIEh0dHBQcm92aWRlciA9IGZ1bmN0aW9uIChob3N0KSB7XG4gICAgdGhpcy5ob3N0ID0gaG9zdCB8fCAnaHR0cDovL2xvY2FsaG9zdDo4NTQ1Jztcbn07XG5cbkh0dHBQcm92aWRlci5wcm90b3R5cGUuc2VuZCA9IGZ1bmN0aW9uIChwYXlsb2FkKSB7XG4gICAgdmFyIHJlcXVlc3QgPSBuZXcgWE1MSHR0cFJlcXVlc3QoKTtcblxuICAgIHJlcXVlc3Qub3BlbignUE9TVCcsIHRoaXMuaG9zdCwgZmFsc2UpO1xuICAgIFxuICAgIHRyeSB7XG4gICAgICAgIHJlcXVlc3Quc2VuZChKU09OLnN0cmluZ2lmeShwYXlsb2FkKSk7XG4gICAgfSBjYXRjaChlcnJvcikge1xuICAgICAgICB0aHJvdyBlcnJvcnMuSW52YWxpZENvbm5lY3Rpb24odGhpcy5ob3N0KTtcbiAgICB9XG5cblxuICAgIC8vIGNoZWNrIHJlcXVlc3Quc3RhdHVzXG4gICAgLy8gVE9ETzogdGhyb3cgYW4gZXJyb3IgaGVyZSEgaXQgY2Fubm90IHNpbGVudGx5IGZhaWwhISFcbiAgICAvL2lmIChyZXF1ZXN0LnN0YXR1cyAhPT0gMjAwKSB7XG4gICAgICAgIC8vcmV0dXJuO1xuICAgIC8vfVxuXG4gICAgdmFyIHJlc3VsdCA9IHJlcXVlc3QucmVzcG9uc2VUZXh0O1xuXG4gICAgdHJ5IHtcbiAgICAgICAgcmVzdWx0ID0gSlNPTi5wYXJzZShyZXN1bHQpO1xuICAgIH0gY2F0Y2goZSkge1xuICAgICAgICB0aHJvdyBlcnJvcnMuSW52YWxpZFJlc3BvbnNlKHJlc3VsdCk7ICAgICAgICAgICAgICAgIFxuICAgIH1cblxuICAgIHJldHVybiByZXN1bHQ7XG59O1xuXG5IdHRwUHJvdmlkZXIucHJvdG90eXBlLnNlbmRBc3luYyA9IGZ1bmN0aW9uIChwYXlsb2FkLCBjYWxsYmFjaykge1xuICAgIHZhciByZXF1ZXN0ID0gbmV3IFhNTEh0dHBSZXF1ZXN0KCk7XG4gICAgcmVxdWVzdC5vbnJlYWR5c3RhdGVjaGFuZ2UgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgaWYgKHJlcXVlc3QucmVhZHlTdGF0ZSA9PT0gNCkge1xuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHJlcXVlc3QucmVzcG9uc2VUZXh0O1xuICAgICAgICAgICAgdmFyIGVycm9yID0gbnVsbDtcblxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICByZXN1bHQgPSBKU09OLnBhcnNlKHJlc3VsdCk7XG4gICAgICAgICAgICB9IGNhdGNoKGUpIHtcbiAgICAgICAgICAgICAgICBlcnJvciA9IGVycm9ycy5JbnZhbGlkUmVzcG9uc2UocmVzdWx0KTsgICAgICAgICAgICAgICAgXG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNhbGxiYWNrKGVycm9yLCByZXN1bHQpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHJlcXVlc3Qub3BlbignUE9TVCcsIHRoaXMuaG9zdCwgdHJ1ZSk7XG5cbiAgICB0cnkge1xuICAgICAgICByZXF1ZXN0LnNlbmQoSlNPTi5zdHJpbmdpZnkocGF5bG9hZCkpO1xuICAgIH0gY2F0Y2goZXJyb3IpIHtcbiAgICAgICAgY2FsbGJhY2soZXJyb3JzLkludmFsaWRDb25uZWN0aW9uKHRoaXMuaG9zdCkpO1xuICAgIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gSHR0cFByb3ZpZGVyO1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBcbiAqIEBmaWxlIGljYXAuanNcbiAqIEBhdXRob3IgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE1XG4gKi9cblxudmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMvdXRpbHMnKTtcblxuLyoqXG4gKiBUaGlzIHByb3RvdHlwZSBzaG91bGQgYmUgdXNlZCB0byBleHRyYWN0IG5lY2Vzc2FyeSBpbmZvcm1hdGlvbiBmcm9tIGliYW4gYWRkcmVzc1xuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBpYmFuXG4gKi9cbnZhciBJQ0FQID0gZnVuY3Rpb24gKGliYW4pIHtcbiAgICB0aGlzLl9pYmFuID0gaWJhbjtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBjaGVjayBpZiBpY2FwIGlzIGNvcnJlY3RcbiAqXG4gKiBAbWV0aG9kIGlzVmFsaWRcbiAqIEByZXR1cm5zIHtCb29sZWFufSB0cnVlIGlmIGl0IGlzLCBvdGhlcndpc2UgZmFsc2VcbiAqL1xuSUNBUC5wcm90b3R5cGUuaXNWYWxpZCA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdXRpbHMuaXNJQkFOKHRoaXMuX2liYW4pO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGNoZWNrIGlmIGliYW4gbnVtYmVyIGlzIGRpcmVjdFxuICpcbiAqIEBtZXRob2QgaXNEaXJlY3RcbiAqIEByZXR1cm5zIHtCb29sZWFufSB0cnVlIGlmIGl0IGlzLCBvdGhlcndpc2UgZmFsc2VcbiAqL1xuSUNBUC5wcm90b3R5cGUuaXNEaXJlY3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2liYW4ubGVuZ3RoID09PSAzNDtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBjaGVjayBpZiBpYmFuIG51bWJlciBpZiBpbmRpcmVjdFxuICpcbiAqIEBtZXRob2QgaXNJbmRpcmVjdFxuICogQHJldHVybnMge0Jvb2xlYW59IHRydWUgaWYgaXQgaXMsIG90aGVyd2lzZSBmYWxzZVxuICovXG5JQ0FQLnByb3RvdHlwZS5pc0luZGlyZWN0ID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLl9pYmFuLmxlbmd0aCA9PT0gMjA7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZ2V0IGliYW4gY2hlY2tzdW1cbiAqIFVzZXMgdGhlIG1vZC05Ny0xMCBjaGVja3N1bW1pbmcgcHJvdG9jb2wgKElTTy9JRUMgNzA2NDoyMDAzKVxuICpcbiAqIEBtZXRob2QgY2hlY2tzdW1cbiAqIEByZXR1cm5zIHtTdHJpbmd9IGNoZWNrc3VtXG4gKi9cbklDQVAucHJvdG90eXBlLmNoZWNrc3VtID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLl9pYmFuLnN1YnN0cigyLCAyKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBnZXQgaW5zdGl0dXRpb24gaWRlbnRpZmllclxuICogZWcuIFhSRUdcbiAqXG4gKiBAbWV0aG9kIGluc3RpdHV0aW9uXG4gKiBAcmV0dXJucyB7U3RyaW5nfSBpbnN0aXR1dGlvbiBpZGVudGlmaWVyXG4gKi9cbklDQVAucHJvdG90eXBlLmluc3RpdHV0aW9uID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLmlzSW5kaXJlY3QoKSA/IHRoaXMuX2liYW4uc3Vic3RyKDcsIDQpIDogJyc7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZ2V0IGNsaWVudCBpZGVudGlmaWVyIHdpdGhpbiBpbnN0aXR1dGlvblxuICogZWcuIEdBVk9GWU9SS1xuICpcbiAqIEBtZXRob2QgY2xpZW50XG4gKiBAcmV0dXJucyB7U3RyaW5nfSBjbGllbnQgaWRlbnRpZmllclxuICovXG5JQ0FQLnByb3RvdHlwZS5jbGllbnQgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuaXNJbmRpcmVjdCgpID8gdGhpcy5faWJhbi5zdWJzdHIoMTEpIDogJyc7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZ2V0IGNsaWVudCBkaXJlY3QgYWRkcmVzc1xuICpcbiAqIEBtZXRob2QgYWRkcmVzc1xuICogQHJldHVybnMge1N0cmluZ30gY2xpZW50IGRpcmVjdCBhZGRyZXNzXG4gKi9cbklDQVAucHJvdG90eXBlLmFkZHJlc3MgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuaXNEaXJlY3QoKSA/IHRoaXMuX2liYW4uc3Vic3RyKDQpIDogJyc7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IElDQVA7XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqIEBmaWxlIGpzb25ycGMuanNcbiAqIEBhdXRob3JzOlxuICogICBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgSnNvbnJwYyA9IGZ1bmN0aW9uICgpIHtcbiAgICAvLyBzaW5nbGV0b24gcGF0dGVyblxuICAgIGlmIChhcmd1bWVudHMuY2FsbGVlLl9zaW5nbGV0b25JbnN0YW5jZSkge1xuICAgICAgICByZXR1cm4gYXJndW1lbnRzLmNhbGxlZS5fc2luZ2xldG9uSW5zdGFuY2U7XG4gICAgfVxuICAgIGFyZ3VtZW50cy5jYWxsZWUuX3NpbmdsZXRvbkluc3RhbmNlID0gdGhpcztcblxuICAgIHRoaXMubWVzc2FnZUlkID0gMTtcbn07XG5cbi8qKlxuICogQHJldHVybiB7SnNvbnJwY30gc2luZ2xldG9uXG4gKi9cbkpzb25ycGMuZ2V0SW5zdGFuY2UgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGluc3RhbmNlID0gbmV3IEpzb25ycGMoKTtcbiAgICByZXR1cm4gaW5zdGFuY2U7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gdmFsaWQganNvbiBjcmVhdGUgcGF5bG9hZCBvYmplY3RcbiAqXG4gKiBAbWV0aG9kIHRvUGF5bG9hZFxuICogQHBhcmFtIHtGdW5jdGlvbn0gbWV0aG9kIG9mIGpzb25ycGMgY2FsbCwgcmVxdWlyZWRcbiAqIEBwYXJhbSB7QXJyYXl9IHBhcmFtcywgYW4gYXJyYXkgb2YgbWV0aG9kIHBhcmFtcywgb3B0aW9uYWxcbiAqIEByZXR1cm5zIHtPYmplY3R9IHZhbGlkIGpzb25ycGMgcGF5bG9hZCBvYmplY3RcbiAqL1xuSnNvbnJwYy5wcm90b3R5cGUudG9QYXlsb2FkID0gZnVuY3Rpb24gKG1ldGhvZCwgcGFyYW1zKSB7XG4gICAgaWYgKCFtZXRob2QpXG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ2pzb25ycGMgbWV0aG9kIHNob3VsZCBiZSBzcGVjaWZpZWQhJyk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgICBqc29ucnBjOiAnMi4wJyxcbiAgICAgICAgbWV0aG9kOiBtZXRob2QsXG4gICAgICAgIHBhcmFtczogcGFyYW1zIHx8IFtdLFxuICAgICAgICBpZDogdGhpcy5tZXNzYWdlSWQrK1xuICAgIH07XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gY2hlY2sgaWYganNvbnJwYyByZXNwb25zZSBpcyB2YWxpZFxuICpcbiAqIEBtZXRob2QgaXNWYWxpZFJlc3BvbnNlXG4gKiBAcGFyYW0ge09iamVjdH1cbiAqIEByZXR1cm5zIHtCb29sZWFufSB0cnVlIGlmIHJlc3BvbnNlIGlzIHZhbGlkLCBvdGhlcndpc2UgZmFsc2VcbiAqL1xuSnNvbnJwYy5wcm90b3R5cGUuaXNWYWxpZFJlc3BvbnNlID0gZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgcmV0dXJuICEhcmVzcG9uc2UgJiZcbiAgICAgICAgIXJlc3BvbnNlLmVycm9yICYmXG4gICAgICAgIHJlc3BvbnNlLmpzb25ycGMgPT09ICcyLjAnICYmXG4gICAgICAgIHR5cGVvZiByZXNwb25zZS5pZCA9PT0gJ251bWJlcicgJiZcbiAgICAgICAgcmVzcG9uc2UucmVzdWx0ICE9PSB1bmRlZmluZWQ7IC8vIG9ubHkgdW5kZWZpbmVkIGlzIG5vdCB2YWxpZCBqc29uIG9iamVjdFxufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGNyZWF0ZSBiYXRjaCBwYXlsb2FkIG9iamVjdFxuICpcbiAqIEBtZXRob2QgdG9CYXRjaFBheWxvYWRcbiAqIEBwYXJhbSB7QXJyYXl9IG1lc3NhZ2VzLCBhbiBhcnJheSBvZiBvYmplY3RzIHdpdGggbWV0aG9kIChyZXF1aXJlZCkgYW5kIHBhcmFtcyAob3B0aW9uYWwpIGZpZWxkc1xuICogQHJldHVybnMge0FycmF5fSBiYXRjaCBwYXlsb2FkXG4gKi9cbkpzb25ycGMucHJvdG90eXBlLnRvQmF0Y2hQYXlsb2FkID0gZnVuY3Rpb24gKG1lc3NhZ2VzKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHJldHVybiBtZXNzYWdlcy5tYXAoZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgcmV0dXJuIHNlbGYudG9QYXlsb2FkKG1lc3NhZ2UubWV0aG9kLCBtZXNzYWdlLnBhcmFtcyk7XG4gICAgfSk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEpzb25ycGM7XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqXG4gKiBAZmlsZSBtZXRob2QuanNcbiAqIEBhdXRob3IgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE1XG4gKi9cblxudmFyIFJlcXVlc3RNYW5hZ2VyID0gcmVxdWlyZSgnLi9yZXF1ZXN0bWFuYWdlcicpO1xudmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMvdXRpbHMnKTtcbnZhciBlcnJvcnMgPSByZXF1aXJlKCcuL2Vycm9ycycpO1xuXG52YXIgTWV0aG9kID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICB0aGlzLm5hbWUgPSBvcHRpb25zLm5hbWU7XG4gICAgdGhpcy5jYWxsID0gb3B0aW9ucy5jYWxsO1xuICAgIHRoaXMucGFyYW1zID0gb3B0aW9ucy5wYXJhbXMgfHwgMDtcbiAgICB0aGlzLmlucHV0Rm9ybWF0dGVyID0gb3B0aW9ucy5pbnB1dEZvcm1hdHRlcjtcbiAgICB0aGlzLm91dHB1dEZvcm1hdHRlciA9IG9wdGlvbnMub3V0cHV0Rm9ybWF0dGVyO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBkZXRlcm1pbmUgbmFtZSBvZiB0aGUganNvbnJwYyBtZXRob2QgYmFzZWQgb24gYXJndW1lbnRzXG4gKlxuICogQG1ldGhvZCBnZXRDYWxsXG4gKiBAcGFyYW0ge0FycmF5fSBhcmd1bWVudHNcbiAqIEByZXR1cm4ge1N0cmluZ30gbmFtZSBvZiBqc29ucnBjIG1ldGhvZFxuICovXG5NZXRob2QucHJvdG90eXBlLmdldENhbGwgPSBmdW5jdGlvbiAoYXJncykge1xuICAgIHJldHVybiB1dGlscy5pc0Z1bmN0aW9uKHRoaXMuY2FsbCkgPyB0aGlzLmNhbGwoYXJncykgOiB0aGlzLmNhbGw7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGV4dHJhY3QgY2FsbGJhY2sgZnJvbSBhcnJheSBvZiBhcmd1bWVudHMuIE1vZGlmaWVzIGlucHV0IHBhcmFtXG4gKlxuICogQG1ldGhvZCBleHRyYWN0Q2FsbGJhY2tcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3VtZW50c1xuICogQHJldHVybiB7RnVuY3Rpb258TnVsbH0gY2FsbGJhY2ssIGlmIGV4aXN0c1xuICovXG5NZXRob2QucHJvdG90eXBlLmV4dHJhY3RDYWxsYmFjayA9IGZ1bmN0aW9uIChhcmdzKSB7XG4gICAgaWYgKHV0aWxzLmlzRnVuY3Rpb24oYXJnc1thcmdzLmxlbmd0aCAtIDFdKSkge1xuICAgICAgICByZXR1cm4gYXJncy5wb3AoKTsgLy8gbW9kaWZ5IHRoZSBhcmdzIGFycmF5IVxuICAgIH1cbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBjaGVjayBpZiB0aGUgbnVtYmVyIG9mIGFyZ3VtZW50cyBpcyBjb3JyZWN0XG4gKiBcbiAqIEBtZXRob2QgdmFsaWRhdGVBcmdzXG4gKiBAcGFyYW0ge0FycmF5fSBhcmd1bWVudHNcbiAqIEB0aHJvd3Mge0Vycm9yfSBpZiBpdCBpcyBub3RcbiAqL1xuTWV0aG9kLnByb3RvdHlwZS52YWxpZGF0ZUFyZ3MgPSBmdW5jdGlvbiAoYXJncykge1xuICAgIGlmIChhcmdzLmxlbmd0aCAhPT0gdGhpcy5wYXJhbXMpIHtcbiAgICAgICAgdGhyb3cgZXJyb3JzLkludmFsaWROdW1iZXJPZlBhcmFtcygpO1xuICAgIH1cbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBmb3JtYXQgaW5wdXQgYXJncyBvZiBtZXRob2RcbiAqIFxuICogQG1ldGhvZCBmb3JtYXRJbnB1dFxuICogQHBhcmFtIHtBcnJheX1cbiAqIEByZXR1cm4ge0FycmF5fVxuICovXG5NZXRob2QucHJvdG90eXBlLmZvcm1hdElucHV0ID0gZnVuY3Rpb24gKGFyZ3MpIHtcbiAgICBpZiAoIXRoaXMuaW5wdXRGb3JtYXR0ZXIpIHtcbiAgICAgICAgcmV0dXJuIGFyZ3M7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuaW5wdXRGb3JtYXR0ZXIubWFwKGZ1bmN0aW9uIChmb3JtYXR0ZXIsIGluZGV4KSB7XG4gICAgICAgIHJldHVybiBmb3JtYXR0ZXIgPyBmb3JtYXR0ZXIoYXJnc1tpbmRleF0pIDogYXJnc1tpbmRleF07XG4gICAgfSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZm9ybWF0IG91dHB1dChyZXN1bHQpIG9mIG1ldGhvZFxuICpcbiAqIEBtZXRob2QgZm9ybWF0T3V0cHV0XG4gKiBAcGFyYW0ge09iamVjdH1cbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuTWV0aG9kLnByb3RvdHlwZS5mb3JtYXRPdXRwdXQgPSBmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgcmV0dXJuIHRoaXMub3V0cHV0Rm9ybWF0dGVyICYmIHJlc3VsdCAhPT0gbnVsbCA/IHRoaXMub3V0cHV0Rm9ybWF0dGVyKHJlc3VsdCkgOiByZXN1bHQ7XG59O1xuXG4vKipcbiAqIFNob3VsZCBhdHRhY2ggZnVuY3Rpb24gdG8gbWV0aG9kXG4gKiBcbiAqIEBtZXRob2QgYXR0YWNoVG9PYmplY3RcbiAqIEBwYXJhbSB7T2JqZWN0fVxuICogQHBhcmFtIHtGdW5jdGlvbn1cbiAqL1xuTWV0aG9kLnByb3RvdHlwZS5hdHRhY2hUb09iamVjdCA9IGZ1bmN0aW9uIChvYmopIHtcbiAgICB2YXIgZnVuYyA9IHRoaXMuc2VuZC5iaW5kKHRoaXMpO1xuICAgIGZ1bmMucmVxdWVzdCA9IHRoaXMucmVxdWVzdC5iaW5kKHRoaXMpO1xuICAgIGZ1bmMuY2FsbCA9IHRoaXMuY2FsbDsgLy8gdGhhdCdzIHVnbHkuIGZpbHRlci5qcyB1c2VzIGl0XG4gICAgdmFyIG5hbWUgPSB0aGlzLm5hbWUuc3BsaXQoJy4nKTtcbiAgICBpZiAobmFtZS5sZW5ndGggPiAxKSB7XG4gICAgICAgIG9ialtuYW1lWzBdXSA9IG9ialtuYW1lWzBdXSB8fCB7fTtcbiAgICAgICAgb2JqW25hbWVbMF1dW25hbWVbMV1dID0gZnVuYztcbiAgICB9IGVsc2Uge1xuICAgICAgICBvYmpbbmFtZVswXV0gPSBmdW5jOyBcbiAgICB9XG59O1xuXG4vKipcbiAqIFNob3VsZCBjcmVhdGUgcGF5bG9hZCBmcm9tIGdpdmVuIGlucHV0IGFyZ3NcbiAqXG4gKiBAbWV0aG9kIHRvUGF5bG9hZFxuICogQHBhcmFtIHtBcnJheX0gYXJnc1xuICogQHJldHVybiB7T2JqZWN0fVxuICovXG5NZXRob2QucHJvdG90eXBlLnRvUGF5bG9hZCA9IGZ1bmN0aW9uIChhcmdzKSB7XG4gICAgdmFyIGNhbGwgPSB0aGlzLmdldENhbGwoYXJncyk7XG4gICAgdmFyIGNhbGxiYWNrID0gdGhpcy5leHRyYWN0Q2FsbGJhY2soYXJncyk7XG4gICAgdmFyIHBhcmFtcyA9IHRoaXMuZm9ybWF0SW5wdXQoYXJncyk7XG4gICAgdGhpcy52YWxpZGF0ZUFyZ3MocGFyYW1zKTtcblxuICAgIHJldHVybiB7XG4gICAgICAgIG1ldGhvZDogY2FsbCxcbiAgICAgICAgcGFyYW1zOiBwYXJhbXMsXG4gICAgICAgIGNhbGxiYWNrOiBjYWxsYmFja1xuICAgIH07XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gY3JlYXRlIHB1cmUgSlNPTlJQQyByZXF1ZXN0IHdoaWNoIGNhbiBiZSB1c2VkIGluIGJhdGNoIHJlcXVlc3RcbiAqXG4gKiBAbWV0aG9kIHJlcXVlc3RcbiAqIEBwYXJhbSB7Li4ufSBwYXJhbXNcbiAqIEByZXR1cm4ge09iamVjdH0ganNvbnJwYyByZXF1ZXN0XG4gKi9cbk1ldGhvZC5wcm90b3R5cGUucmVxdWVzdCA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgcGF5bG9hZCA9IHRoaXMudG9QYXlsb2FkKEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cykpO1xuICAgIHBheWxvYWQuZm9ybWF0ID0gdGhpcy5mb3JtYXRPdXRwdXQuYmluZCh0aGlzKTtcbiAgICByZXR1cm4gcGF5bG9hZDtcbn07XG5cbi8qKlxuICogU2hvdWxkIHNlbmQgcmVxdWVzdCB0byB0aGUgQVBJXG4gKlxuICogQG1ldGhvZCBzZW5kXG4gKiBAcGFyYW0gbGlzdCBvZiBwYXJhbXNcbiAqIEByZXR1cm4gcmVzdWx0XG4gKi9cbk1ldGhvZC5wcm90b3R5cGUuc2VuZCA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgcGF5bG9hZCA9IHRoaXMudG9QYXlsb2FkKEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cykpO1xuICAgIGlmIChwYXlsb2FkLmNhbGxiYWNrKSB7XG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgcmV0dXJuIFJlcXVlc3RNYW5hZ2VyLmdldEluc3RhbmNlKCkuc2VuZEFzeW5jKHBheWxvYWQsIGZ1bmN0aW9uIChlcnIsIHJlc3VsdCkge1xuICAgICAgICAgICAgcGF5bG9hZC5jYWxsYmFjayhlcnIsIHNlbGYuZm9ybWF0T3V0cHV0KHJlc3VsdCkpO1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuZm9ybWF0T3V0cHV0KFJlcXVlc3RNYW5hZ2VyLmdldEluc3RhbmNlKCkuc2VuZChwYXlsb2FkKSk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1ldGhvZDtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogXG4gKiBAZmlsZSBuYW1lcmVnLmpzXG4gKiBAYXV0aG9yIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbnZhciBjb250cmFjdCA9IHJlcXVpcmUoJy4vY29udHJhY3QnKTtcblxudmFyIGFkZHJlc3MgPSAnMHhjNmQ5ZDJjZDQ0OWE3NTRjNDk0MjY0ZTE4MDljNTBlMzRkNjQ1NjJiJztcblxudmFyIGFiaSA9IFtcbiAgICB7XCJjb25zdGFudFwiOnRydWUsXCJpbnB1dHNcIjpbe1wibmFtZVwiOlwiX293bmVyXCIsXCJ0eXBlXCI6XCJhZGRyZXNzXCJ9XSxcIm5hbWVcIjpcIm5hbWVcIixcIm91dHB1dHNcIjpbe1wibmFtZVwiOlwib19uYW1lXCIsXCJ0eXBlXCI6XCJieXRlczMyXCJ9XSxcInR5cGVcIjpcImZ1bmN0aW9uXCJ9LFxuICAgIHtcImNvbnN0YW50XCI6dHJ1ZSxcImlucHV0c1wiOlt7XCJuYW1lXCI6XCJfbmFtZVwiLFwidHlwZVwiOlwiYnl0ZXMzMlwifV0sXCJuYW1lXCI6XCJvd25lclwiLFwib3V0cHV0c1wiOlt7XCJuYW1lXCI6XCJcIixcInR5cGVcIjpcImFkZHJlc3NcIn1dLFwidHlwZVwiOlwiZnVuY3Rpb25cIn0sXG4gICAge1wiY29uc3RhbnRcIjp0cnVlLFwiaW5wdXRzXCI6W3tcIm5hbWVcIjpcIl9uYW1lXCIsXCJ0eXBlXCI6XCJieXRlczMyXCJ9XSxcIm5hbWVcIjpcImNvbnRlbnRcIixcIm91dHB1dHNcIjpbe1wibmFtZVwiOlwiXCIsXCJ0eXBlXCI6XCJieXRlczMyXCJ9XSxcInR5cGVcIjpcImZ1bmN0aW9uXCJ9LFxuICAgIHtcImNvbnN0YW50XCI6dHJ1ZSxcImlucHV0c1wiOlt7XCJuYW1lXCI6XCJfbmFtZVwiLFwidHlwZVwiOlwiYnl0ZXMzMlwifV0sXCJuYW1lXCI6XCJhZGRyXCIsXCJvdXRwdXRzXCI6W3tcIm5hbWVcIjpcIlwiLFwidHlwZVwiOlwiYWRkcmVzc1wifV0sXCJ0eXBlXCI6XCJmdW5jdGlvblwifSxcbiAgICB7XCJjb25zdGFudFwiOmZhbHNlLFwiaW5wdXRzXCI6W3tcIm5hbWVcIjpcIl9uYW1lXCIsXCJ0eXBlXCI6XCJieXRlczMyXCJ9XSxcIm5hbWVcIjpcInJlc2VydmVcIixcIm91dHB1dHNcIjpbXSxcInR5cGVcIjpcImZ1bmN0aW9uXCJ9LFxuICAgIHtcImNvbnN0YW50XCI6dHJ1ZSxcImlucHV0c1wiOlt7XCJuYW1lXCI6XCJfbmFtZVwiLFwidHlwZVwiOlwiYnl0ZXMzMlwifV0sXCJuYW1lXCI6XCJzdWJSZWdpc3RyYXJcIixcIm91dHB1dHNcIjpbe1wibmFtZVwiOlwib19zdWJSZWdpc3RyYXJcIixcInR5cGVcIjpcImFkZHJlc3NcIn1dLFwidHlwZVwiOlwiZnVuY3Rpb25cIn0sXG4gICAge1wiY29uc3RhbnRcIjpmYWxzZSxcImlucHV0c1wiOlt7XCJuYW1lXCI6XCJfbmFtZVwiLFwidHlwZVwiOlwiYnl0ZXMzMlwifSx7XCJuYW1lXCI6XCJfbmV3T3duZXJcIixcInR5cGVcIjpcImFkZHJlc3NcIn1dLFwibmFtZVwiOlwidHJhbnNmZXJcIixcIm91dHB1dHNcIjpbXSxcInR5cGVcIjpcImZ1bmN0aW9uXCJ9LFxuICAgIHtcImNvbnN0YW50XCI6ZmFsc2UsXCJpbnB1dHNcIjpbe1wibmFtZVwiOlwiX25hbWVcIixcInR5cGVcIjpcImJ5dGVzMzJcIn0se1wibmFtZVwiOlwiX3JlZ2lzdHJhclwiLFwidHlwZVwiOlwiYWRkcmVzc1wifV0sXCJuYW1lXCI6XCJzZXRTdWJSZWdpc3RyYXJcIixcIm91dHB1dHNcIjpbXSxcInR5cGVcIjpcImZ1bmN0aW9uXCJ9LFxuICAgIHtcImNvbnN0YW50XCI6ZmFsc2UsXCJpbnB1dHNcIjpbXSxcIm5hbWVcIjpcIlJlZ2lzdHJhclwiLFwib3V0cHV0c1wiOltdLFwidHlwZVwiOlwiZnVuY3Rpb25cIn0sXG4gICAge1wiY29uc3RhbnRcIjpmYWxzZSxcImlucHV0c1wiOlt7XCJuYW1lXCI6XCJfbmFtZVwiLFwidHlwZVwiOlwiYnl0ZXMzMlwifSx7XCJuYW1lXCI6XCJfYVwiLFwidHlwZVwiOlwiYWRkcmVzc1wifSx7XCJuYW1lXCI6XCJfcHJpbWFyeVwiLFwidHlwZVwiOlwiYm9vbFwifV0sXCJuYW1lXCI6XCJzZXRBZGRyZXNzXCIsXCJvdXRwdXRzXCI6W10sXCJ0eXBlXCI6XCJmdW5jdGlvblwifSxcbiAgICB7XCJjb25zdGFudFwiOmZhbHNlLFwiaW5wdXRzXCI6W3tcIm5hbWVcIjpcIl9uYW1lXCIsXCJ0eXBlXCI6XCJieXRlczMyXCJ9LHtcIm5hbWVcIjpcIl9jb250ZW50XCIsXCJ0eXBlXCI6XCJieXRlczMyXCJ9XSxcIm5hbWVcIjpcInNldENvbnRlbnRcIixcIm91dHB1dHNcIjpbXSxcInR5cGVcIjpcImZ1bmN0aW9uXCJ9LFxuICAgIHtcImNvbnN0YW50XCI6ZmFsc2UsXCJpbnB1dHNcIjpbe1wibmFtZVwiOlwiX25hbWVcIixcInR5cGVcIjpcImJ5dGVzMzJcIn1dLFwibmFtZVwiOlwiZGlzb3duXCIsXCJvdXRwdXRzXCI6W10sXCJ0eXBlXCI6XCJmdW5jdGlvblwifSxcbiAgICB7XCJjb25zdGFudFwiOnRydWUsXCJpbnB1dHNcIjpbe1wibmFtZVwiOlwiX25hbWVcIixcInR5cGVcIjpcImJ5dGVzMzJcIn1dLFwibmFtZVwiOlwicmVnaXN0ZXJcIixcIm91dHB1dHNcIjpbe1wibmFtZVwiOlwiXCIsXCJ0eXBlXCI6XCJhZGRyZXNzXCJ9XSxcInR5cGVcIjpcImZ1bmN0aW9uXCJ9LFxuICAgIHtcImFub255bW91c1wiOmZhbHNlLFwiaW5wdXRzXCI6W3tcImluZGV4ZWRcIjp0cnVlLFwibmFtZVwiOlwibmFtZVwiLFwidHlwZVwiOlwiYnl0ZXMzMlwifV0sXCJuYW1lXCI6XCJDaGFuZ2VkXCIsXCJ0eXBlXCI6XCJldmVudFwifSxcbiAgICB7XCJhbm9ueW1vdXNcIjpmYWxzZSxcImlucHV0c1wiOlt7XCJpbmRleGVkXCI6dHJ1ZSxcIm5hbWVcIjpcIm5hbWVcIixcInR5cGVcIjpcImJ5dGVzMzJcIn0se1wiaW5kZXhlZFwiOnRydWUsXCJuYW1lXCI6XCJhZGRyXCIsXCJ0eXBlXCI6XCJhZGRyZXNzXCJ9XSxcIm5hbWVcIjpcIlByaW1hcnlDaGFuZ2VkXCIsXCJ0eXBlXCI6XCJldmVudFwifVxuXTtcblxubW9kdWxlLmV4cG9ydHMgPSBjb250cmFjdChhYmkpLmF0KGFkZHJlc3MpO1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBAZmlsZSBldGguanNcbiAqIEBhdXRob3JzOlxuICogICBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy91dGlscycpO1xudmFyIFByb3BlcnR5ID0gcmVxdWlyZSgnLi9wcm9wZXJ0eScpO1xuXG4vLy8gQHJldHVybnMgYW4gYXJyYXkgb2Ygb2JqZWN0cyBkZXNjcmliaW5nIHdlYjMuZXRoIGFwaSBtZXRob2RzXG52YXIgbWV0aG9kcyA9IFtcbl07XG5cbi8vLyBAcmV0dXJucyBhbiBhcnJheSBvZiBvYmplY3RzIGRlc2NyaWJpbmcgd2ViMy5ldGggYXBpIHByb3BlcnRpZXNcbnZhciBwcm9wZXJ0aWVzID0gW1xuICAgIG5ldyBQcm9wZXJ0eSh7XG4gICAgICAgIG5hbWU6ICdsaXN0ZW5pbmcnLFxuICAgICAgICBnZXR0ZXI6ICduZXRfbGlzdGVuaW5nJ1xuICAgIH0pLFxuICAgIG5ldyBQcm9wZXJ0eSh7XG4gICAgICAgIG5hbWU6ICdwZWVyQ291bnQnLFxuICAgICAgICBnZXR0ZXI6ICduZXRfcGVlckNvdW50JyxcbiAgICAgICAgb3V0cHV0Rm9ybWF0dGVyOiB1dGlscy50b0RlY2ltYWxcbiAgICB9KVxuXTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBtZXRob2RzOiBtZXRob2RzLFxuICAgIHByb3BlcnRpZXM6IHByb3BlcnRpZXNcbn07XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqXG4gKiBAZmlsZSBwcm9wZXJ0eS5qc1xuICogQGF1dGhvciBGYWJpYW4gVm9nZWxzdGVsbGVyIDxmYWJpYW5AZnJvemVtYW4uZGU+XG4gKiBAYXV0aG9yIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbnZhciBSZXF1ZXN0TWFuYWdlciA9IHJlcXVpcmUoJy4vcmVxdWVzdG1hbmFnZXInKTtcblxudmFyIFByb3BlcnR5ID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICB0aGlzLm5hbWUgPSBvcHRpb25zLm5hbWU7XG4gICAgdGhpcy5nZXR0ZXIgPSBvcHRpb25zLmdldHRlcjtcbiAgICB0aGlzLnNldHRlciA9IG9wdGlvbnMuc2V0dGVyO1xuICAgIHRoaXMub3V0cHV0Rm9ybWF0dGVyID0gb3B0aW9ucy5vdXRwdXRGb3JtYXR0ZXI7XG4gICAgdGhpcy5pbnB1dEZvcm1hdHRlciA9IG9wdGlvbnMuaW5wdXRGb3JtYXR0ZXI7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZm9ybWF0IGlucHV0IGFyZ3Mgb2YgbWV0aG9kXG4gKiBcbiAqIEBtZXRob2QgZm9ybWF0SW5wdXRcbiAqIEBwYXJhbSB7QXJyYXl9XG4gKiBAcmV0dXJuIHtBcnJheX1cbiAqL1xuUHJvcGVydHkucHJvdG90eXBlLmZvcm1hdElucHV0ID0gZnVuY3Rpb24gKGFyZykge1xuICAgIHJldHVybiB0aGlzLmlucHV0Rm9ybWF0dGVyID8gdGhpcy5pbnB1dEZvcm1hdHRlcihhcmcpIDogYXJnO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGZvcm1hdCBvdXRwdXQocmVzdWx0KSBvZiBtZXRob2RcbiAqXG4gKiBAbWV0aG9kIGZvcm1hdE91dHB1dFxuICogQHBhcmFtIHtPYmplY3R9XG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cblByb3BlcnR5LnByb3RvdHlwZS5mb3JtYXRPdXRwdXQgPSBmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgcmV0dXJuIHRoaXMub3V0cHV0Rm9ybWF0dGVyICYmIHJlc3VsdCAhPT0gbnVsbCA/IHRoaXMub3V0cHV0Rm9ybWF0dGVyKHJlc3VsdCkgOiByZXN1bHQ7XG59O1xuXG4vKipcbiAqIFNob3VsZCBhdHRhY2ggZnVuY3Rpb24gdG8gbWV0aG9kXG4gKiBcbiAqIEBtZXRob2QgYXR0YWNoVG9PYmplY3RcbiAqIEBwYXJhbSB7T2JqZWN0fVxuICogQHBhcmFtIHtGdW5jdGlvbn1cbiAqL1xuUHJvcGVydHkucHJvdG90eXBlLmF0dGFjaFRvT2JqZWN0ID0gZnVuY3Rpb24gKG9iaikge1xuICAgIHZhciBwcm90byA9IHtcbiAgICAgICAgZ2V0OiB0aGlzLmdldC5iaW5kKHRoaXMpLFxuICAgIH07XG5cbiAgICB2YXIgbmFtZXMgPSB0aGlzLm5hbWUuc3BsaXQoJy4nKTtcbiAgICB2YXIgbmFtZSA9IG5hbWVzWzBdO1xuICAgIGlmIChuYW1lcy5sZW5ndGggPiAxKSB7XG4gICAgICAgIG9ialtuYW1lc1swXV0gPSBvYmpbbmFtZXNbMF1dIHx8IHt9O1xuICAgICAgICBvYmogPSBvYmpbbmFtZXNbMF1dO1xuICAgICAgICBuYW1lID0gbmFtZXNbMV07XG4gICAgfVxuICAgIFxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShvYmosIG5hbWUsIHByb3RvKTtcblxuICAgIHZhciB0b0FzeW5jTmFtZSA9IGZ1bmN0aW9uIChwcmVmaXgsIG5hbWUpIHtcbiAgICAgICAgcmV0dXJuIHByZWZpeCArIG5hbWUuY2hhckF0KDApLnRvVXBwZXJDYXNlKCkgKyBuYW1lLnNsaWNlKDEpO1xuICAgIH07XG5cbiAgICBvYmpbdG9Bc3luY05hbWUoJ2dldCcsIG5hbWUpXSA9IHRoaXMuZ2V0QXN5bmMuYmluZCh0aGlzKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZ2V0IHZhbHVlIG9mIHRoZSBwcm9wZXJ0eVxuICpcbiAqIEBtZXRob2QgZ2V0XG4gKiBAcmV0dXJuIHtPYmplY3R9IHZhbHVlIG9mIHRoZSBwcm9wZXJ0eVxuICovXG5Qcm9wZXJ0eS5wcm90b3R5cGUuZ2V0ID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLmZvcm1hdE91dHB1dChSZXF1ZXN0TWFuYWdlci5nZXRJbnN0YW5jZSgpLnNlbmQoe1xuICAgICAgICBtZXRob2Q6IHRoaXMuZ2V0dGVyXG4gICAgfSkpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBhc3luY2hyb3Vub3VzbHkgZ2V0IHZhbHVlIG9mIHByb3BlcnR5XG4gKlxuICogQG1ldGhvZCBnZXRBc3luY1xuICogQHBhcmFtIHtGdW5jdGlvbn1cbiAqL1xuUHJvcGVydHkucHJvdG90eXBlLmdldEFzeW5jID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIFJlcXVlc3RNYW5hZ2VyLmdldEluc3RhbmNlKCkuc2VuZEFzeW5jKHtcbiAgICAgICAgbWV0aG9kOiB0aGlzLmdldHRlclxuICAgIH0sIGZ1bmN0aW9uIChlcnIsIHJlc3VsdCkge1xuICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICByZXR1cm4gY2FsbGJhY2soZXJyKTtcbiAgICAgICAgfVxuICAgICAgICBjYWxsYmFjayhlcnIsIHNlbGYuZm9ybWF0T3V0cHV0KHJlc3VsdCkpO1xuICAgIH0pO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBQcm9wZXJ0eTtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogQGZpbGUgcXRzeW5jLmpzXG4gKiBAYXV0aG9yczpcbiAqICAgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiAgIE1hcmlhbiBPYW5jZWEgPG1hcmlhbkBldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNFxuICovXG5cbnZhciBRdFN5bmNQcm92aWRlciA9IGZ1bmN0aW9uICgpIHtcbn07XG5cblF0U3luY1Byb3ZpZGVyLnByb3RvdHlwZS5zZW5kID0gZnVuY3Rpb24gKHBheWxvYWQpIHtcbiAgICB2YXIgcmVzdWx0ID0gbmF2aWdhdG9yLnF0LmNhbGxNZXRob2QoSlNPTi5zdHJpbmdpZnkocGF5bG9hZCkpO1xuICAgIHJldHVybiBKU09OLnBhcnNlKHJlc3VsdCk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFF0U3luY1Byb3ZpZGVyO1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBcbiAqIEBmaWxlIHJlcXVlc3RtYW5hZ2VyLmpzXG4gKiBAYXV0aG9yIEplZmZyZXkgV2lsY2tlIDxqZWZmQGV0aGRldi5jb20+XG4gKiBAYXV0aG9yIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGF1dGhvciBNYXJpYW4gT2FuY2VhIDxtYXJpYW5AZXRoZGV2LmNvbT5cbiAqIEBhdXRob3IgRmFiaWFuIFZvZ2Vsc3RlbGxlciA8ZmFiaWFuQGV0aGRldi5jb20+XG4gKiBAYXV0aG9yIEdhdiBXb29kIDxnQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE0XG4gKi9cblxudmFyIEpzb25ycGMgPSByZXF1aXJlKCcuL2pzb25ycGMnKTtcbnZhciB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzL3V0aWxzJyk7XG52YXIgYyA9IHJlcXVpcmUoJy4uL3V0aWxzL2NvbmZpZycpO1xudmFyIGVycm9ycyA9IHJlcXVpcmUoJy4vZXJyb3JzJyk7XG5cbi8qKlxuICogSXQncyByZXNwb25zaWJsZSBmb3IgcGFzc2luZyBtZXNzYWdlcyB0byBwcm92aWRlcnNcbiAqIEl0J3MgYWxzbyByZXNwb25zaWJsZSBmb3IgcG9sbGluZyB0aGUgZXRoZXJldW0gbm9kZSBmb3IgaW5jb21pbmcgbWVzc2FnZXNcbiAqIERlZmF1bHQgcG9sbCB0aW1lb3V0IGlzIDEgc2Vjb25kXG4gKiBTaW5nbGV0b25cbiAqL1xudmFyIFJlcXVlc3RNYW5hZ2VyID0gZnVuY3Rpb24gKHByb3ZpZGVyKSB7XG4gICAgLy8gc2luZ2xldG9uIHBhdHRlcm5cbiAgICBpZiAoYXJndW1lbnRzLmNhbGxlZS5fc2luZ2xldG9uSW5zdGFuY2UpIHtcbiAgICAgICAgcmV0dXJuIGFyZ3VtZW50cy5jYWxsZWUuX3NpbmdsZXRvbkluc3RhbmNlO1xuICAgIH1cbiAgICBhcmd1bWVudHMuY2FsbGVlLl9zaW5nbGV0b25JbnN0YW5jZSA9IHRoaXM7XG5cbiAgICB0aGlzLnByb3ZpZGVyID0gcHJvdmlkZXI7XG4gICAgdGhpcy5wb2xscyA9IFtdO1xuICAgIHRoaXMudGltZW91dCA9IG51bGw7XG4gICAgdGhpcy5wb2xsKCk7XG59O1xuXG4vKipcbiAqIEByZXR1cm4ge1JlcXVlc3RNYW5hZ2VyfSBzaW5nbGV0b25cbiAqL1xuUmVxdWVzdE1hbmFnZXIuZ2V0SW5zdGFuY2UgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGluc3RhbmNlID0gbmV3IFJlcXVlc3RNYW5hZ2VyKCk7XG4gICAgcmV0dXJuIGluc3RhbmNlO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBzeW5jaHJvbm91c2x5IHNlbmQgcmVxdWVzdFxuICpcbiAqIEBtZXRob2Qgc2VuZFxuICogQHBhcmFtIHtPYmplY3R9IGRhdGFcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuUmVxdWVzdE1hbmFnZXIucHJvdG90eXBlLnNlbmQgPSBmdW5jdGlvbiAoZGF0YSkge1xuICAgIGlmICghdGhpcy5wcm92aWRlcikge1xuICAgICAgICBjb25zb2xlLmVycm9yKGVycm9ycy5JbnZhbGlkUHJvdmlkZXIoKSk7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHZhciBwYXlsb2FkID0gSnNvbnJwYy5nZXRJbnN0YW5jZSgpLnRvUGF5bG9hZChkYXRhLm1ldGhvZCwgZGF0YS5wYXJhbXMpO1xuICAgIHZhciByZXN1bHQgPSB0aGlzLnByb3ZpZGVyLnNlbmQocGF5bG9hZCk7XG5cbiAgICBpZiAoIUpzb25ycGMuZ2V0SW5zdGFuY2UoKS5pc1ZhbGlkUmVzcG9uc2UocmVzdWx0KSkge1xuICAgICAgICB0aHJvdyBlcnJvcnMuSW52YWxpZFJlc3BvbnNlKHJlc3VsdCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdC5yZXN1bHQ7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGFzeW5jaHJvbm91c2x5IHNlbmQgcmVxdWVzdFxuICpcbiAqIEBtZXRob2Qgc2VuZEFzeW5jXG4gKiBAcGFyYW0ge09iamVjdH0gZGF0YVxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2tcbiAqL1xuUmVxdWVzdE1hbmFnZXIucHJvdG90eXBlLnNlbmRBc3luYyA9IGZ1bmN0aW9uIChkYXRhLCBjYWxsYmFjaykge1xuICAgIGlmICghdGhpcy5wcm92aWRlcikge1xuICAgICAgICByZXR1cm4gY2FsbGJhY2soZXJyb3JzLkludmFsaWRQcm92aWRlcigpKTtcbiAgICB9XG5cbiAgICB2YXIgcGF5bG9hZCA9IEpzb25ycGMuZ2V0SW5zdGFuY2UoKS50b1BheWxvYWQoZGF0YS5tZXRob2QsIGRhdGEucGFyYW1zKTtcbiAgICB0aGlzLnByb3ZpZGVyLnNlbmRBc3luYyhwYXlsb2FkLCBmdW5jdGlvbiAoZXJyLCByZXN1bHQpIHtcbiAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgcmV0dXJuIGNhbGxiYWNrKGVycik7XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIGlmICghSnNvbnJwYy5nZXRJbnN0YW5jZSgpLmlzVmFsaWRSZXNwb25zZShyZXN1bHQpKSB7XG4gICAgICAgICAgICByZXR1cm4gY2FsbGJhY2soZXJyb3JzLkludmFsaWRSZXNwb25zZShyZXN1bHQpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNhbGxiYWNrKG51bGwsIHJlc3VsdC5yZXN1bHQpO1xuICAgIH0pO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGFzeW5jaHJvbm91c2x5IHNlbmQgYmF0Y2ggcmVxdWVzdFxuICpcbiAqIEBtZXRob2Qgc2VuZEJhdGNoXG4gKiBAcGFyYW0ge0FycmF5fSBiYXRjaCBkYXRhXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFja1xuICovXG5SZXF1ZXN0TWFuYWdlci5wcm90b3R5cGUuc2VuZEJhdGNoID0gZnVuY3Rpb24gKGRhdGEsIGNhbGxiYWNrKSB7XG4gICAgaWYgKCF0aGlzLnByb3ZpZGVyKSB7XG4gICAgICAgIHJldHVybiBjYWxsYmFjayhlcnJvcnMuSW52YWxpZFByb3ZpZGVyKCkpO1xuICAgIH1cblxuICAgIHZhciBwYXlsb2FkID0gSnNvbnJwYy5nZXRJbnN0YW5jZSgpLnRvQmF0Y2hQYXlsb2FkKGRhdGEpO1xuXG4gICAgdGhpcy5wcm92aWRlci5zZW5kQXN5bmMocGF5bG9hZCwgZnVuY3Rpb24gKGVyciwgcmVzdWx0cykge1xuICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICByZXR1cm4gY2FsbGJhY2soZXJyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghdXRpbHMuaXNBcnJheShyZXN1bHRzKSkge1xuICAgICAgICAgICAgcmV0dXJuIGNhbGxiYWNrKGVycm9ycy5JbnZhbGlkUmVzcG9uc2UocmVzdWx0cykpO1xuICAgICAgICB9XG5cbiAgICAgICAgY2FsbGJhY2soZXJyLCByZXN1bHRzKTtcbiAgICB9KTsgXG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIHNldCBwcm92aWRlciBvZiByZXF1ZXN0IG1hbmFnZXJcbiAqXG4gKiBAbWV0aG9kIHNldFByb3ZpZGVyXG4gKiBAcGFyYW0ge09iamVjdH1cbiAqL1xuUmVxdWVzdE1hbmFnZXIucHJvdG90eXBlLnNldFByb3ZpZGVyID0gZnVuY3Rpb24gKHApIHtcbiAgICB0aGlzLnByb3ZpZGVyID0gcDtcbn07XG5cbi8qanNoaW50IG1heHBhcmFtczo0ICovXG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gc3RhcnQgcG9sbGluZ1xuICpcbiAqIEBtZXRob2Qgc3RhcnRQb2xsaW5nXG4gKiBAcGFyYW0ge09iamVjdH0gZGF0YVxuICogQHBhcmFtIHtOdW1iZXJ9IHBvbGxJZFxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2tcbiAqIEBwYXJhbSB7RnVuY3Rpb259IHVuaW5zdGFsbFxuICpcbiAqIEB0b2RvIGNsZWFudXAgbnVtYmVyIG9mIHBhcmFtc1xuICovXG5SZXF1ZXN0TWFuYWdlci5wcm90b3R5cGUuc3RhcnRQb2xsaW5nID0gZnVuY3Rpb24gKGRhdGEsIHBvbGxJZCwgY2FsbGJhY2ssIHVuaW5zdGFsbCkge1xuICAgIHRoaXMucG9sbHMucHVzaCh7ZGF0YTogZGF0YSwgaWQ6IHBvbGxJZCwgY2FsbGJhY2s6IGNhbGxiYWNrLCB1bmluc3RhbGw6IHVuaW5zdGFsbH0pO1xufTtcbi8qanNoaW50IG1heHBhcmFtczozICovXG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gc3RvcCBwb2xsaW5nIGZvciBmaWx0ZXIgd2l0aCBnaXZlbiBpZFxuICpcbiAqIEBtZXRob2Qgc3RvcFBvbGxpbmdcbiAqIEBwYXJhbSB7TnVtYmVyfSBwb2xsSWRcbiAqL1xuUmVxdWVzdE1hbmFnZXIucHJvdG90eXBlLnN0b3BQb2xsaW5nID0gZnVuY3Rpb24gKHBvbGxJZCkge1xuICAgIGZvciAodmFyIGkgPSB0aGlzLnBvbGxzLmxlbmd0aDsgaS0tOykge1xuICAgICAgICB2YXIgcG9sbCA9IHRoaXMucG9sbHNbaV07XG4gICAgICAgIGlmIChwb2xsLmlkID09PSBwb2xsSWQpIHtcbiAgICAgICAgICAgIHRoaXMucG9sbHMuc3BsaWNlKGksIDEpO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIHJlc2V0IHBvbGxpbmcgbWVjaGFuaXNtIG9mIHJlcXVlc3QgbWFuYWdlclxuICpcbiAqIEBtZXRob2QgcmVzZXRcbiAqL1xuUmVxdWVzdE1hbmFnZXIucHJvdG90eXBlLnJlc2V0ID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMucG9sbHMuZm9yRWFjaChmdW5jdGlvbiAocG9sbCkge1xuICAgICAgICBwb2xsLnVuaW5zdGFsbChwb2xsLmlkKTsgXG4gICAgfSk7XG4gICAgdGhpcy5wb2xscyA9IFtdO1xuXG4gICAgaWYgKHRoaXMudGltZW91dCkge1xuICAgICAgICBjbGVhclRpbWVvdXQodGhpcy50aW1lb3V0KTtcbiAgICAgICAgdGhpcy50aW1lb3V0ID0gbnVsbDtcbiAgICB9XG4gICAgdGhpcy5wb2xsKCk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gcG9sbCBmb3IgY2hhbmdlcyBvbiBmaWx0ZXIgd2l0aCBnaXZlbiBpZFxuICpcbiAqIEBtZXRob2QgcG9sbFxuICovXG5SZXF1ZXN0TWFuYWdlci5wcm90b3R5cGUucG9sbCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnRpbWVvdXQgPSBzZXRUaW1lb3V0KHRoaXMucG9sbC5iaW5kKHRoaXMpLCBjLkVUSF9QT0xMSU5HX1RJTUVPVVQpO1xuXG4gICAgaWYgKCF0aGlzLnBvbGxzLmxlbmd0aCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLnByb3ZpZGVyKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3JzLkludmFsaWRQcm92aWRlcigpKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHZhciBwYXlsb2FkID0gSnNvbnJwYy5nZXRJbnN0YW5jZSgpLnRvQmF0Y2hQYXlsb2FkKHRoaXMucG9sbHMubWFwKGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICAgIHJldHVybiBkYXRhLmRhdGE7XG4gICAgfSkpO1xuXG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHRoaXMucHJvdmlkZXIuc2VuZEFzeW5jKHBheWxvYWQsIGZ1bmN0aW9uIChlcnJvciwgcmVzdWx0cykge1xuICAgICAgICAvLyBUT0RPOiBjb25zb2xlIGxvZz9cbiAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgICAgIFxuICAgICAgICBpZiAoIXV0aWxzLmlzQXJyYXkocmVzdWx0cykpIHtcbiAgICAgICAgICAgIHRocm93IGVycm9ycy5JbnZhbGlkUmVzcG9uc2UocmVzdWx0cyk7XG4gICAgICAgIH1cblxuICAgICAgICByZXN1bHRzLm1hcChmdW5jdGlvbiAocmVzdWx0LCBpbmRleCkge1xuICAgICAgICAgICAgcmVzdWx0LmNhbGxiYWNrID0gc2VsZi5wb2xsc1tpbmRleF0uY2FsbGJhY2s7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9KS5maWx0ZXIoZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgdmFyIHZhbGlkID0gSnNvbnJwYy5nZXRJbnN0YW5jZSgpLmlzVmFsaWRSZXNwb25zZShyZXN1bHQpO1xuICAgICAgICAgICAgaWYgKCF2YWxpZCkge1xuICAgICAgICAgICAgICAgIHJlc3VsdC5jYWxsYmFjayhlcnJvcnMuSW52YWxpZFJlc3BvbnNlKHJlc3VsdCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHZhbGlkO1xuICAgICAgICB9KS5maWx0ZXIoZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgcmV0dXJuIHV0aWxzLmlzQXJyYXkocmVzdWx0LnJlc3VsdCkgJiYgcmVzdWx0LnJlc3VsdC5sZW5ndGggPiAwO1xuICAgICAgICB9KS5mb3JFYWNoKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgICAgIHJlc3VsdC5jYWxsYmFjayhudWxsLCByZXN1bHQucmVzdWx0KTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlcXVlc3RNYW5hZ2VyO1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBAZmlsZSBzaGguanNcbiAqIEBhdXRob3JzOlxuICogICBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgTWV0aG9kID0gcmVxdWlyZSgnLi9tZXRob2QnKTtcbnZhciBmb3JtYXR0ZXJzID0gcmVxdWlyZSgnLi9mb3JtYXR0ZXJzJyk7XG5cbnZhciBwb3N0ID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ3Bvc3QnLCBcbiAgICBjYWxsOiAnc2hoX3Bvc3QnLCBcbiAgICBwYXJhbXM6IDEsXG4gICAgaW5wdXRGb3JtYXR0ZXI6IFtmb3JtYXR0ZXJzLmlucHV0UG9zdEZvcm1hdHRlcl1cbn0pO1xuXG52YXIgbmV3SWRlbnRpdHkgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnbmV3SWRlbnRpdHknLFxuICAgIGNhbGw6ICdzaGhfbmV3SWRlbnRpdHknLFxuICAgIHBhcmFtczogMFxufSk7XG5cbnZhciBoYXNJZGVudGl0eSA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdoYXNJZGVudGl0eScsXG4gICAgY2FsbDogJ3NoaF9oYXNJZGVudGl0eScsXG4gICAgcGFyYW1zOiAxXG59KTtcblxudmFyIG5ld0dyb3VwID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ25ld0dyb3VwJyxcbiAgICBjYWxsOiAnc2hoX25ld0dyb3VwJyxcbiAgICBwYXJhbXM6IDBcbn0pO1xuXG52YXIgYWRkVG9Hcm91cCA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdhZGRUb0dyb3VwJyxcbiAgICBjYWxsOiAnc2hoX2FkZFRvR3JvdXAnLFxuICAgIHBhcmFtczogMFxufSk7XG5cbnZhciBtZXRob2RzID0gW1xuICAgIHBvc3QsXG4gICAgbmV3SWRlbnRpdHksXG4gICAgaGFzSWRlbnRpdHksXG4gICAgbmV3R3JvdXAsXG4gICAgYWRkVG9Hcm91cFxuXTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgbWV0aG9kczogbWV0aG9kc1xufTtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogXG4gKiBAZmlsZSB0cmFuc2Zlci5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgd2ViMyA9IHJlcXVpcmUoJy4uL3dlYjMnKTtcbnZhciBJQ0FQID0gcmVxdWlyZSgnLi9pY2FwJyk7XG52YXIgbmFtZXJlZyA9IHJlcXVpcmUoJy4vbmFtZXJlZycpO1xudmFyIGNvbnRyYWN0ID0gcmVxdWlyZSgnLi9jb250cmFjdCcpO1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIG1ha2UgSUNBUCB0cmFuc2ZlclxuICpcbiAqIEBtZXRob2QgdHJhbnNmZXJcbiAqIEBwYXJhbSB7U3RyaW5nfSBpYmFuIG51bWJlclxuICogQHBhcmFtIHtTdHJpbmd9IGZyb20gKGFkZHJlc3MpXG4gKiBAcGFyYW0ge1ZhbHVlfSB2YWx1ZSB0byBiZSB0cmFuZmVyZWRcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrLCBjYWxsYmFja1xuICovXG52YXIgdHJhbnNmZXIgPSBmdW5jdGlvbiAoZnJvbSwgaWJhbiwgdmFsdWUsIGNhbGxiYWNrKSB7XG4gICAgdmFyIGljYXAgPSBuZXcgSUNBUChpYmFuKTsgXG4gICAgaWYgKCFpY2FwLmlzVmFsaWQoKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgaWJhbiBhZGRyZXNzJyk7XG4gICAgfVxuXG4gICAgaWYgKGljYXAuaXNEaXJlY3QoKSkge1xuICAgICAgICByZXR1cm4gdHJhbnNmZXJUb0FkZHJlc3MoZnJvbSwgaWNhcC5hZGRyZXNzKCksIHZhbHVlLCBjYWxsYmFjayk7XG4gICAgfVxuICAgIFxuICAgIGlmICghY2FsbGJhY2spIHtcbiAgICAgICAgdmFyIGFkZHJlc3MgPSBuYW1lcmVnLmFkZHIoaWNhcC5pbnN0aXR1dGlvbigpKTtcbiAgICAgICAgcmV0dXJuIGRlcG9zaXQoZnJvbSwgYWRkcmVzcywgdmFsdWUsIGljYXAuY2xpZW50KCkpO1xuICAgIH1cblxuICAgIG5hbWVyZWcuYWRkcihpY2FwLmluc2l0dXRpb24oKSwgZnVuY3Rpb24gKGVyciwgYWRkcmVzcykge1xuICAgICAgICByZXR1cm4gZGVwb3NpdChmcm9tLCBhZGRyZXNzLCB2YWx1ZSwgaWNhcC5jbGllbnQoKSwgY2FsbGJhY2spO1xuICAgIH0pO1xuICAgIFxufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byB0cmFuc2ZlciBmdW5kcyB0byBjZXJ0YWluIGFkZHJlc3NcbiAqXG4gKiBAbWV0aG9kIHRyYW5zZmVyVG9BZGRyZXNzXG4gKiBAcGFyYW0ge1N0cmluZ30gYWRkcmVzc1xuICogQHBhcmFtIHtTdHJpbmd9IGZyb20gKGFkZHJlc3MpXG4gKiBAcGFyYW0ge1ZhbHVlfSB2YWx1ZSB0byBiZSB0cmFuZmVyZWRcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrLCBjYWxsYmFja1xuICovXG52YXIgdHJhbnNmZXJUb0FkZHJlc3MgPSBmdW5jdGlvbiAoZnJvbSwgYWRkcmVzcywgdmFsdWUsIGNhbGxiYWNrKSB7XG4gICAgcmV0dXJuIHdlYjMuZXRoLnNlbmRUcmFuc2FjdGlvbih7XG4gICAgICAgIGFkZHJlc3M6IGFkZHJlc3MsXG4gICAgICAgIGZyb206IGZyb20sXG4gICAgICAgIHZhbHVlOiB2YWx1ZVxuICAgIH0sIGNhbGxiYWNrKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZGVwb3NpdCBmdW5kcyB0byBnZW5lcmljIEV4Y2hhbmdlIGNvbnRyYWN0IChtdXN0IGltcGxlbWVudCBkZXBvc2l0KGJ5dGVzMzIpIG1ldGhvZCEpXG4gKlxuICogQG1ldGhvZCBkZXBvc2l0XG4gKiBAcGFyYW0ge1N0cmluZ30gYWRkcmVzc1xuICogQHBhcmFtIHtTdHJpbmd9IGZyb20gKGFkZHJlc3MpXG4gKiBAcGFyYW0ge1ZhbHVlfSB2YWx1ZSB0byBiZSB0cmFuZmVyZWRcbiAqIEBwYXJhbSB7U3RyaW5nfSBjbGllbnQgdW5pcXVlIGlkZW50aWZpZXJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrLCBjYWxsYmFja1xuICovXG52YXIgZGVwb3NpdCA9IGZ1bmN0aW9uIChmcm9tLCBhZGRyZXNzLCB2YWx1ZSwgY2xpZW50LCBjYWxsYmFjaykge1xuICAgIHZhciBhYmkgPSBbe1wiY29uc3RhbnRcIjpmYWxzZSxcImlucHV0c1wiOlt7XCJuYW1lXCI6XCJuYW1lXCIsXCJ0eXBlXCI6XCJieXRlczMyXCJ9XSxcIm5hbWVcIjpcImRlcG9zaXRcIixcIm91dHB1dHNcIjpbXSxcInR5cGVcIjpcImZ1bmN0aW9uXCJ9XTtcbiAgICByZXR1cm4gY29udHJhY3QoYWJpKS5hdChhZGRyZXNzKS5kZXBvc2l0KGNsaWVudCwge1xuICAgICAgICBmcm9tOiBmcm9tLFxuICAgICAgICB2YWx1ZTogdmFsdWVcbiAgICB9LCBjYWxsYmFjayk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IHRyYW5zZmVyO1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBAZmlsZSB3YXRjaGVzLmpzXG4gKiBAYXV0aG9yczpcbiAqICAgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE1XG4gKi9cblxudmFyIE1ldGhvZCA9IHJlcXVpcmUoJy4vbWV0aG9kJyk7XG5cbi8vLyBAcmV0dXJucyBhbiBhcnJheSBvZiBvYmplY3RzIGRlc2NyaWJpbmcgd2ViMy5ldGguZmlsdGVyIGFwaSBtZXRob2RzXG52YXIgZXRoID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBuZXdGaWx0ZXJDYWxsID0gZnVuY3Rpb24gKGFyZ3MpIHtcbiAgICAgICAgdmFyIHR5cGUgPSBhcmdzWzBdO1xuXG4gICAgICAgIHN3aXRjaCh0eXBlKSB7XG4gICAgICAgICAgICBjYXNlICdsYXRlc3QnOlxuICAgICAgICAgICAgICAgIGFyZ3MucG9wKCk7XG4gICAgICAgICAgICAgICAgdGhpcy5wYXJhbXMgPSAwO1xuICAgICAgICAgICAgICAgIHJldHVybiAnZXRoX25ld0Jsb2NrRmlsdGVyJztcbiAgICAgICAgICAgIGNhc2UgJ3BlbmRpbmcnOlxuICAgICAgICAgICAgICAgIGFyZ3MucG9wKCk7XG4gICAgICAgICAgICAgICAgdGhpcy5wYXJhbXMgPSAwO1xuICAgICAgICAgICAgICAgIHJldHVybiAnZXRoX25ld1BlbmRpbmdUcmFuc2FjdGlvbkZpbHRlcic7XG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIHJldHVybiAnZXRoX25ld0ZpbHRlcic7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIG5ld0ZpbHRlciA9IG5ldyBNZXRob2Qoe1xuICAgICAgICBuYW1lOiAnbmV3RmlsdGVyJyxcbiAgICAgICAgY2FsbDogbmV3RmlsdGVyQ2FsbCxcbiAgICAgICAgcGFyYW1zOiAxXG4gICAgfSk7XG5cbiAgICB2YXIgdW5pbnN0YWxsRmlsdGVyID0gbmV3IE1ldGhvZCh7XG4gICAgICAgIG5hbWU6ICd1bmluc3RhbGxGaWx0ZXInLFxuICAgICAgICBjYWxsOiAnZXRoX3VuaW5zdGFsbEZpbHRlcicsXG4gICAgICAgIHBhcmFtczogMVxuICAgIH0pO1xuXG4gICAgdmFyIGdldExvZ3MgPSBuZXcgTWV0aG9kKHtcbiAgICAgICAgbmFtZTogJ2dldExvZ3MnLFxuICAgICAgICBjYWxsOiAnZXRoX2dldEZpbHRlckxvZ3MnLFxuICAgICAgICBwYXJhbXM6IDFcbiAgICB9KTtcblxuICAgIHZhciBwb2xsID0gbmV3IE1ldGhvZCh7XG4gICAgICAgIG5hbWU6ICdwb2xsJyxcbiAgICAgICAgY2FsbDogJ2V0aF9nZXRGaWx0ZXJDaGFuZ2VzJyxcbiAgICAgICAgcGFyYW1zOiAxXG4gICAgfSk7XG5cbiAgICByZXR1cm4gW1xuICAgICAgICBuZXdGaWx0ZXIsXG4gICAgICAgIHVuaW5zdGFsbEZpbHRlcixcbiAgICAgICAgZ2V0TG9ncyxcbiAgICAgICAgcG9sbFxuICAgIF07XG59O1xuXG4vLy8gQHJldHVybnMgYW4gYXJyYXkgb2Ygb2JqZWN0cyBkZXNjcmliaW5nIHdlYjMuc2hoLndhdGNoIGFwaSBtZXRob2RzXG52YXIgc2hoID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBuZXdGaWx0ZXIgPSBuZXcgTWV0aG9kKHtcbiAgICAgICAgbmFtZTogJ25ld0ZpbHRlcicsXG4gICAgICAgIGNhbGw6ICdzaGhfbmV3RmlsdGVyJyxcbiAgICAgICAgcGFyYW1zOiAxXG4gICAgfSk7XG5cbiAgICB2YXIgdW5pbnN0YWxsRmlsdGVyID0gbmV3IE1ldGhvZCh7XG4gICAgICAgIG5hbWU6ICd1bmluc3RhbGxGaWx0ZXInLFxuICAgICAgICBjYWxsOiAnc2hoX3VuaW5zdGFsbEZpbHRlcicsXG4gICAgICAgIHBhcmFtczogMVxuICAgIH0pO1xuXG4gICAgdmFyIGdldExvZ3MgPSBuZXcgTWV0aG9kKHtcbiAgICAgICAgbmFtZTogJ2dldExvZ3MnLFxuICAgICAgICBjYWxsOiAnc2hoX2dldE1lc3NhZ2VzJyxcbiAgICAgICAgcGFyYW1zOiAxXG4gICAgfSk7XG5cbiAgICB2YXIgcG9sbCA9IG5ldyBNZXRob2Qoe1xuICAgICAgICBuYW1lOiAncG9sbCcsXG4gICAgICAgIGNhbGw6ICdzaGhfZ2V0RmlsdGVyQ2hhbmdlcycsXG4gICAgICAgIHBhcmFtczogMVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIFtcbiAgICAgICAgbmV3RmlsdGVyLFxuICAgICAgICB1bmluc3RhbGxGaWx0ZXIsXG4gICAgICAgIGdldExvZ3MsXG4gICAgICAgIHBvbGxcbiAgICBdO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgZXRoOiBldGgsXG4gICAgc2hoOiBzaGhcbn07XG5cbiIsbnVsbCwiOyhmdW5jdGlvbiAocm9vdCwgZmFjdG9yeSkge1xuXHRpZiAodHlwZW9mIGV4cG9ydHMgPT09IFwib2JqZWN0XCIpIHtcblx0XHQvLyBDb21tb25KU1xuXHRcdG1vZHVsZS5leHBvcnRzID0gZXhwb3J0cyA9IGZhY3RvcnkoKTtcblx0fVxuXHRlbHNlIGlmICh0eXBlb2YgZGVmaW5lID09PSBcImZ1bmN0aW9uXCIgJiYgZGVmaW5lLmFtZCkge1xuXHRcdC8vIEFNRFxuXHRcdGRlZmluZShbXSwgZmFjdG9yeSk7XG5cdH1cblx0ZWxzZSB7XG5cdFx0Ly8gR2xvYmFsIChicm93c2VyKVxuXHRcdHJvb3QuQ3J5cHRvSlMgPSBmYWN0b3J5KCk7XG5cdH1cbn0odGhpcywgZnVuY3Rpb24gKCkge1xuXG5cdC8qKlxuXHQgKiBDcnlwdG9KUyBjb3JlIGNvbXBvbmVudHMuXG5cdCAqL1xuXHR2YXIgQ3J5cHRvSlMgPSBDcnlwdG9KUyB8fCAoZnVuY3Rpb24gKE1hdGgsIHVuZGVmaW5lZCkge1xuXHQgICAgLyoqXG5cdCAgICAgKiBDcnlwdG9KUyBuYW1lc3BhY2UuXG5cdCAgICAgKi9cblx0ICAgIHZhciBDID0ge307XG5cblx0ICAgIC8qKlxuXHQgICAgICogTGlicmFyeSBuYW1lc3BhY2UuXG5cdCAgICAgKi9cblx0ICAgIHZhciBDX2xpYiA9IEMubGliID0ge307XG5cblx0ICAgIC8qKlxuXHQgICAgICogQmFzZSBvYmplY3QgZm9yIHByb3RvdHlwYWwgaW5oZXJpdGFuY2UuXG5cdCAgICAgKi9cblx0ICAgIHZhciBCYXNlID0gQ19saWIuQmFzZSA9IChmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgZnVuY3Rpb24gRigpIHt9XG5cblx0ICAgICAgICByZXR1cm4ge1xuXHQgICAgICAgICAgICAvKipcblx0ICAgICAgICAgICAgICogQ3JlYXRlcyBhIG5ldyBvYmplY3QgdGhhdCBpbmhlcml0cyBmcm9tIHRoaXMgb2JqZWN0LlxuXHQgICAgICAgICAgICAgKlxuXHQgICAgICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3ZlcnJpZGVzIFByb3BlcnRpZXMgdG8gY29weSBpbnRvIHRoZSBuZXcgb2JqZWN0LlxuXHQgICAgICAgICAgICAgKlxuXHQgICAgICAgICAgICAgKiBAcmV0dXJuIHtPYmplY3R9IFRoZSBuZXcgb2JqZWN0LlxuXHQgICAgICAgICAgICAgKlxuXHQgICAgICAgICAgICAgKiBAc3RhdGljXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqICAgICB2YXIgTXlUeXBlID0gQ3J5cHRvSlMubGliLkJhc2UuZXh0ZW5kKHtcblx0ICAgICAgICAgICAgICogICAgICAgICBmaWVsZDogJ3ZhbHVlJyxcblx0ICAgICAgICAgICAgICpcblx0ICAgICAgICAgICAgICogICAgICAgICBtZXRob2Q6IGZ1bmN0aW9uICgpIHtcblx0ICAgICAgICAgICAgICogICAgICAgICB9XG5cdCAgICAgICAgICAgICAqICAgICB9KTtcblx0ICAgICAgICAgICAgICovXG5cdCAgICAgICAgICAgIGV4dGVuZDogZnVuY3Rpb24gKG92ZXJyaWRlcykge1xuXHQgICAgICAgICAgICAgICAgLy8gU3Bhd25cblx0ICAgICAgICAgICAgICAgIEYucHJvdG90eXBlID0gdGhpcztcblx0ICAgICAgICAgICAgICAgIHZhciBzdWJ0eXBlID0gbmV3IEYoKTtcblxuXHQgICAgICAgICAgICAgICAgLy8gQXVnbWVudFxuXHQgICAgICAgICAgICAgICAgaWYgKG92ZXJyaWRlcykge1xuXHQgICAgICAgICAgICAgICAgICAgIHN1YnR5cGUubWl4SW4ob3ZlcnJpZGVzKTtcblx0ICAgICAgICAgICAgICAgIH1cblxuXHQgICAgICAgICAgICAgICAgLy8gQ3JlYXRlIGRlZmF1bHQgaW5pdGlhbGl6ZXJcblx0ICAgICAgICAgICAgICAgIGlmICghc3VidHlwZS5oYXNPd25Qcm9wZXJ0eSgnaW5pdCcpKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgc3VidHlwZS5pbml0ID0gZnVuY3Rpb24gKCkge1xuXHQgICAgICAgICAgICAgICAgICAgICAgICBzdWJ0eXBlLiRzdXBlci5pbml0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cdCAgICAgICAgICAgICAgICAgICAgfTtcblx0ICAgICAgICAgICAgICAgIH1cblxuXHQgICAgICAgICAgICAgICAgLy8gSW5pdGlhbGl6ZXIncyBwcm90b3R5cGUgaXMgdGhlIHN1YnR5cGUgb2JqZWN0XG5cdCAgICAgICAgICAgICAgICBzdWJ0eXBlLmluaXQucHJvdG90eXBlID0gc3VidHlwZTtcblxuXHQgICAgICAgICAgICAgICAgLy8gUmVmZXJlbmNlIHN1cGVydHlwZVxuXHQgICAgICAgICAgICAgICAgc3VidHlwZS4kc3VwZXIgPSB0aGlzO1xuXG5cdCAgICAgICAgICAgICAgICByZXR1cm4gc3VidHlwZTtcblx0ICAgICAgICAgICAgfSxcblxuXHQgICAgICAgICAgICAvKipcblx0ICAgICAgICAgICAgICogRXh0ZW5kcyB0aGlzIG9iamVjdCBhbmQgcnVucyB0aGUgaW5pdCBtZXRob2QuXG5cdCAgICAgICAgICAgICAqIEFyZ3VtZW50cyB0byBjcmVhdGUoKSB3aWxsIGJlIHBhc3NlZCB0byBpbml0KCkuXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqIEByZXR1cm4ge09iamVjdH0gVGhlIG5ldyBvYmplY3QuXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqIEBzdGF0aWNcblx0ICAgICAgICAgICAgICpcblx0ICAgICAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgICAgICpcblx0ICAgICAgICAgICAgICogICAgIHZhciBpbnN0YW5jZSA9IE15VHlwZS5jcmVhdGUoKTtcblx0ICAgICAgICAgICAgICovXG5cdCAgICAgICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKCkge1xuXHQgICAgICAgICAgICAgICAgdmFyIGluc3RhbmNlID0gdGhpcy5leHRlbmQoKTtcblx0ICAgICAgICAgICAgICAgIGluc3RhbmNlLmluaXQuYXBwbHkoaW5zdGFuY2UsIGFyZ3VtZW50cyk7XG5cblx0ICAgICAgICAgICAgICAgIHJldHVybiBpbnN0YW5jZTtcblx0ICAgICAgICAgICAgfSxcblxuXHQgICAgICAgICAgICAvKipcblx0ICAgICAgICAgICAgICogSW5pdGlhbGl6ZXMgYSBuZXdseSBjcmVhdGVkIG9iamVjdC5cblx0ICAgICAgICAgICAgICogT3ZlcnJpZGUgdGhpcyBtZXRob2QgdG8gYWRkIHNvbWUgbG9naWMgd2hlbiB5b3VyIG9iamVjdHMgYXJlIGNyZWF0ZWQuXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqICAgICB2YXIgTXlUeXBlID0gQ3J5cHRvSlMubGliLkJhc2UuZXh0ZW5kKHtcblx0ICAgICAgICAgICAgICogICAgICAgICBpbml0OiBmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgICAgICAqICAgICAgICAgICAgIC8vIC4uLlxuXHQgICAgICAgICAgICAgKiAgICAgICAgIH1cblx0ICAgICAgICAgICAgICogICAgIH0pO1xuXHQgICAgICAgICAgICAgKi9cblx0ICAgICAgICAgICAgaW5pdDogZnVuY3Rpb24gKCkge1xuXHQgICAgICAgICAgICB9LFxuXG5cdCAgICAgICAgICAgIC8qKlxuXHQgICAgICAgICAgICAgKiBDb3BpZXMgcHJvcGVydGllcyBpbnRvIHRoaXMgb2JqZWN0LlxuXHQgICAgICAgICAgICAgKlxuXHQgICAgICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gcHJvcGVydGllcyBUaGUgcHJvcGVydGllcyB0byBtaXggaW4uXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqICAgICBNeVR5cGUubWl4SW4oe1xuXHQgICAgICAgICAgICAgKiAgICAgICAgIGZpZWxkOiAndmFsdWUnXG5cdCAgICAgICAgICAgICAqICAgICB9KTtcblx0ICAgICAgICAgICAgICovXG5cdCAgICAgICAgICAgIG1peEluOiBmdW5jdGlvbiAocHJvcGVydGllcykge1xuXHQgICAgICAgICAgICAgICAgZm9yICh2YXIgcHJvcGVydHlOYW1lIGluIHByb3BlcnRpZXMpIHtcblx0ICAgICAgICAgICAgICAgICAgICBpZiAocHJvcGVydGllcy5oYXNPd25Qcm9wZXJ0eShwcm9wZXJ0eU5hbWUpKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIHRoaXNbcHJvcGVydHlOYW1lXSA9IHByb3BlcnRpZXNbcHJvcGVydHlOYW1lXTtcblx0ICAgICAgICAgICAgICAgICAgICB9XG5cdCAgICAgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgICAgIC8vIElFIHdvbid0IGNvcHkgdG9TdHJpbmcgdXNpbmcgdGhlIGxvb3AgYWJvdmVcblx0ICAgICAgICAgICAgICAgIGlmIChwcm9wZXJ0aWVzLmhhc093blByb3BlcnR5KCd0b1N0cmluZycpKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgdGhpcy50b1N0cmluZyA9IHByb3BlcnRpZXMudG9TdHJpbmc7XG5cdCAgICAgICAgICAgICAgICB9XG5cdCAgICAgICAgICAgIH0sXG5cblx0ICAgICAgICAgICAgLyoqXG5cdCAgICAgICAgICAgICAqIENyZWF0ZXMgYSBjb3B5IG9mIHRoaXMgb2JqZWN0LlxuXHQgICAgICAgICAgICAgKlxuXHQgICAgICAgICAgICAgKiBAcmV0dXJuIHtPYmplY3R9IFRoZSBjbG9uZS5cblx0ICAgICAgICAgICAgICpcblx0ICAgICAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgICAgICpcblx0ICAgICAgICAgICAgICogICAgIHZhciBjbG9uZSA9IGluc3RhbmNlLmNsb25lKCk7XG5cdCAgICAgICAgICAgICAqL1xuXHQgICAgICAgICAgICBjbG9uZTogZnVuY3Rpb24gKCkge1xuXHQgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuaW5pdC5wcm90b3R5cGUuZXh0ZW5kKHRoaXMpO1xuXHQgICAgICAgICAgICB9XG5cdCAgICAgICAgfTtcblx0ICAgIH0oKSk7XG5cblx0ICAgIC8qKlxuXHQgICAgICogQW4gYXJyYXkgb2YgMzItYml0IHdvcmRzLlxuXHQgICAgICpcblx0ICAgICAqIEBwcm9wZXJ0eSB7QXJyYXl9IHdvcmRzIFRoZSBhcnJheSBvZiAzMi1iaXQgd29yZHMuXG5cdCAgICAgKiBAcHJvcGVydHkge251bWJlcn0gc2lnQnl0ZXMgVGhlIG51bWJlciBvZiBzaWduaWZpY2FudCBieXRlcyBpbiB0aGlzIHdvcmQgYXJyYXkuXG5cdCAgICAgKi9cblx0ICAgIHZhciBXb3JkQXJyYXkgPSBDX2xpYi5Xb3JkQXJyYXkgPSBCYXNlLmV4dGVuZCh7XG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogSW5pdGlhbGl6ZXMgYSBuZXdseSBjcmVhdGVkIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge0FycmF5fSB3b3JkcyAoT3B0aW9uYWwpIEFuIGFycmF5IG9mIDMyLWJpdCB3b3Jkcy5cblx0ICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gc2lnQnl0ZXMgKE9wdGlvbmFsKSBUaGUgbnVtYmVyIG9mIHNpZ25pZmljYW50IGJ5dGVzIGluIHRoZSB3b3Jkcy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIHdvcmRBcnJheSA9IENyeXB0b0pTLmxpYi5Xb3JkQXJyYXkuY3JlYXRlKCk7XG5cdCAgICAgICAgICogICAgIHZhciB3b3JkQXJyYXkgPSBDcnlwdG9KUy5saWIuV29yZEFycmF5LmNyZWF0ZShbMHgwMDAxMDIwMywgMHgwNDA1MDYwN10pO1xuXHQgICAgICAgICAqICAgICB2YXIgd29yZEFycmF5ID0gQ3J5cHRvSlMubGliLldvcmRBcnJheS5jcmVhdGUoWzB4MDAwMTAyMDMsIDB4MDQwNTA2MDddLCA2KTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICBpbml0OiBmdW5jdGlvbiAod29yZHMsIHNpZ0J5dGVzKSB7XG5cdCAgICAgICAgICAgIHdvcmRzID0gdGhpcy53b3JkcyA9IHdvcmRzIHx8IFtdO1xuXG5cdCAgICAgICAgICAgIGlmIChzaWdCeXRlcyAhPSB1bmRlZmluZWQpIHtcblx0ICAgICAgICAgICAgICAgIHRoaXMuc2lnQnl0ZXMgPSBzaWdCeXRlcztcblx0ICAgICAgICAgICAgfSBlbHNlIHtcblx0ICAgICAgICAgICAgICAgIHRoaXMuc2lnQnl0ZXMgPSB3b3Jkcy5sZW5ndGggKiA0O1xuXHQgICAgICAgICAgICB9XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIENvbnZlcnRzIHRoaXMgd29yZCBhcnJheSB0byBhIHN0cmluZy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7RW5jb2Rlcn0gZW5jb2RlciAoT3B0aW9uYWwpIFRoZSBlbmNvZGluZyBzdHJhdGVneSB0byB1c2UuIERlZmF1bHQ6IENyeXB0b0pTLmVuYy5IZXhcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge3N0cmluZ30gVGhlIHN0cmluZ2lmaWVkIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciBzdHJpbmcgPSB3b3JkQXJyYXkgKyAnJztcblx0ICAgICAgICAgKiAgICAgdmFyIHN0cmluZyA9IHdvcmRBcnJheS50b1N0cmluZygpO1xuXHQgICAgICAgICAqICAgICB2YXIgc3RyaW5nID0gd29yZEFycmF5LnRvU3RyaW5nKENyeXB0b0pTLmVuYy5VdGY4KTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICB0b1N0cmluZzogZnVuY3Rpb24gKGVuY29kZXIpIHtcblx0ICAgICAgICAgICAgcmV0dXJuIChlbmNvZGVyIHx8IEhleCkuc3RyaW5naWZ5KHRoaXMpO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDb25jYXRlbmF0ZXMgYSB3b3JkIGFycmF5IHRvIHRoaXMgd29yZCBhcnJheS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7V29yZEFycmF5fSB3b3JkQXJyYXkgVGhlIHdvcmQgYXJyYXkgdG8gYXBwZW5kLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7V29yZEFycmF5fSBUaGlzIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHdvcmRBcnJheTEuY29uY2F0KHdvcmRBcnJheTIpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIGNvbmNhdDogZnVuY3Rpb24gKHdvcmRBcnJheSkge1xuXHQgICAgICAgICAgICAvLyBTaG9ydGN1dHNcblx0ICAgICAgICAgICAgdmFyIHRoaXNXb3JkcyA9IHRoaXMud29yZHM7XG5cdCAgICAgICAgICAgIHZhciB0aGF0V29yZHMgPSB3b3JkQXJyYXkud29yZHM7XG5cdCAgICAgICAgICAgIHZhciB0aGlzU2lnQnl0ZXMgPSB0aGlzLnNpZ0J5dGVzO1xuXHQgICAgICAgICAgICB2YXIgdGhhdFNpZ0J5dGVzID0gd29yZEFycmF5LnNpZ0J5dGVzO1xuXG5cdCAgICAgICAgICAgIC8vIENsYW1wIGV4Y2VzcyBiaXRzXG5cdCAgICAgICAgICAgIHRoaXMuY2xhbXAoKTtcblxuXHQgICAgICAgICAgICAvLyBDb25jYXRcblx0ICAgICAgICAgICAgaWYgKHRoaXNTaWdCeXRlcyAlIDQpIHtcblx0ICAgICAgICAgICAgICAgIC8vIENvcHkgb25lIGJ5dGUgYXQgYSB0aW1lXG5cdCAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoYXRTaWdCeXRlczsgaSsrKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgdmFyIHRoYXRCeXRlID0gKHRoYXRXb3Jkc1tpID4+PiAyXSA+Pj4gKDI0IC0gKGkgJSA0KSAqIDgpKSAmIDB4ZmY7XG5cdCAgICAgICAgICAgICAgICAgICAgdGhpc1dvcmRzWyh0aGlzU2lnQnl0ZXMgKyBpKSA+Pj4gMl0gfD0gdGhhdEJ5dGUgPDwgKDI0IC0gKCh0aGlzU2lnQnl0ZXMgKyBpKSAlIDQpICogOCk7XG5cdCAgICAgICAgICAgICAgICB9XG5cdCAgICAgICAgICAgIH0gZWxzZSB7XG5cdCAgICAgICAgICAgICAgICAvLyBDb3B5IG9uZSB3b3JkIGF0IGEgdGltZVxuXHQgICAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGF0U2lnQnl0ZXM7IGkgKz0gNCkge1xuXHQgICAgICAgICAgICAgICAgICAgIHRoaXNXb3Jkc1sodGhpc1NpZ0J5dGVzICsgaSkgPj4+IDJdID0gdGhhdFdvcmRzW2kgPj4+IDJdO1xuXHQgICAgICAgICAgICAgICAgfVxuXHQgICAgICAgICAgICB9XG5cdCAgICAgICAgICAgIHRoaXMuc2lnQnl0ZXMgKz0gdGhhdFNpZ0J5dGVzO1xuXG5cdCAgICAgICAgICAgIC8vIENoYWluYWJsZVxuXHQgICAgICAgICAgICByZXR1cm4gdGhpcztcblx0ICAgICAgICB9LFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogUmVtb3ZlcyBpbnNpZ25pZmljYW50IGJpdHMuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHdvcmRBcnJheS5jbGFtcCgpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIGNsYW1wOiBmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgICAgIC8vIFNob3J0Y3V0c1xuXHQgICAgICAgICAgICB2YXIgd29yZHMgPSB0aGlzLndvcmRzO1xuXHQgICAgICAgICAgICB2YXIgc2lnQnl0ZXMgPSB0aGlzLnNpZ0J5dGVzO1xuXG5cdCAgICAgICAgICAgIC8vIENsYW1wXG5cdCAgICAgICAgICAgIHdvcmRzW3NpZ0J5dGVzID4+PiAyXSAmPSAweGZmZmZmZmZmIDw8ICgzMiAtIChzaWdCeXRlcyAlIDQpICogOCk7XG5cdCAgICAgICAgICAgIHdvcmRzLmxlbmd0aCA9IE1hdGguY2VpbChzaWdCeXRlcyAvIDQpO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDcmVhdGVzIGEgY29weSBvZiB0aGlzIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtXb3JkQXJyYXl9IFRoZSBjbG9uZS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIGNsb25lID0gd29yZEFycmF5LmNsb25lKCk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgY2xvbmU6IGZ1bmN0aW9uICgpIHtcblx0ICAgICAgICAgICAgdmFyIGNsb25lID0gQmFzZS5jbG9uZS5jYWxsKHRoaXMpO1xuXHQgICAgICAgICAgICBjbG9uZS53b3JkcyA9IHRoaXMud29yZHMuc2xpY2UoMCk7XG5cblx0ICAgICAgICAgICAgcmV0dXJuIGNsb25lO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDcmVhdGVzIGEgd29yZCBhcnJheSBmaWxsZWQgd2l0aCByYW5kb20gYnl0ZXMuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gbkJ5dGVzIFRoZSBudW1iZXIgb2YgcmFuZG9tIGJ5dGVzIHRvIGdlbmVyYXRlLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7V29yZEFycmF5fSBUaGUgcmFuZG9tIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAc3RhdGljXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciB3b3JkQXJyYXkgPSBDcnlwdG9KUy5saWIuV29yZEFycmF5LnJhbmRvbSgxNik7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgcmFuZG9tOiBmdW5jdGlvbiAobkJ5dGVzKSB7XG5cdCAgICAgICAgICAgIHZhciB3b3JkcyA9IFtdO1xuXG5cdCAgICAgICAgICAgIHZhciByID0gKGZ1bmN0aW9uIChtX3cpIHtcblx0ICAgICAgICAgICAgICAgIHZhciBtX3cgPSBtX3c7XG5cdCAgICAgICAgICAgICAgICB2YXIgbV96ID0gMHgzYWRlNjhiMTtcblx0ICAgICAgICAgICAgICAgIHZhciBtYXNrID0gMHhmZmZmZmZmZjtcblxuXHQgICAgICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uICgpIHtcblx0ICAgICAgICAgICAgICAgICAgICBtX3ogPSAoMHg5MDY5ICogKG1feiAmIDB4RkZGRikgKyAobV96ID4+IDB4MTApKSAmIG1hc2s7XG5cdCAgICAgICAgICAgICAgICAgICAgbV93ID0gKDB4NDY1MCAqIChtX3cgJiAweEZGRkYpICsgKG1fdyA+PiAweDEwKSkgJiBtYXNrO1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciByZXN1bHQgPSAoKG1feiA8PCAweDEwKSArIG1fdykgJiBtYXNrO1xuXHQgICAgICAgICAgICAgICAgICAgIHJlc3VsdCAvPSAweDEwMDAwMDAwMDtcblx0ICAgICAgICAgICAgICAgICAgICByZXN1bHQgKz0gMC41O1xuXHQgICAgICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQgKiAoTWF0aC5yYW5kb20oKSA+IC41ID8gMSA6IC0xKTtcblx0ICAgICAgICAgICAgICAgIH1cblx0ICAgICAgICAgICAgfSk7XG5cblx0ICAgICAgICAgICAgZm9yICh2YXIgaSA9IDAsIHJjYWNoZTsgaSA8IG5CeXRlczsgaSArPSA0KSB7XG5cdCAgICAgICAgICAgICAgICB2YXIgX3IgPSByKChyY2FjaGUgfHwgTWF0aC5yYW5kb20oKSkgKiAweDEwMDAwMDAwMCk7XG5cblx0ICAgICAgICAgICAgICAgIHJjYWNoZSA9IF9yKCkgKiAweDNhZGU2N2I3O1xuXHQgICAgICAgICAgICAgICAgd29yZHMucHVzaCgoX3IoKSAqIDB4MTAwMDAwMDAwKSB8IDApO1xuXHQgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgcmV0dXJuIG5ldyBXb3JkQXJyYXkuaW5pdCh3b3JkcywgbkJ5dGVzKTtcblx0ICAgICAgICB9XG5cdCAgICB9KTtcblxuXHQgICAgLyoqXG5cdCAgICAgKiBFbmNvZGVyIG5hbWVzcGFjZS5cblx0ICAgICAqL1xuXHQgICAgdmFyIENfZW5jID0gQy5lbmMgPSB7fTtcblxuXHQgICAgLyoqXG5cdCAgICAgKiBIZXggZW5jb2Rpbmcgc3RyYXRlZ3kuXG5cdCAgICAgKi9cblx0ICAgIHZhciBIZXggPSBDX2VuYy5IZXggPSB7XG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogQ29udmVydHMgYSB3b3JkIGFycmF5IHRvIGEgaGV4IHN0cmluZy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7V29yZEFycmF5fSB3b3JkQXJyYXkgVGhlIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBoZXggc3RyaW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHN0YXRpY1xuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgaGV4U3RyaW5nID0gQ3J5cHRvSlMuZW5jLkhleC5zdHJpbmdpZnkod29yZEFycmF5KTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICBzdHJpbmdpZnk6IGZ1bmN0aW9uICh3b3JkQXJyYXkpIHtcblx0ICAgICAgICAgICAgLy8gU2hvcnRjdXRzXG5cdCAgICAgICAgICAgIHZhciB3b3JkcyA9IHdvcmRBcnJheS53b3Jkcztcblx0ICAgICAgICAgICAgdmFyIHNpZ0J5dGVzID0gd29yZEFycmF5LnNpZ0J5dGVzO1xuXG5cdCAgICAgICAgICAgIC8vIENvbnZlcnRcblx0ICAgICAgICAgICAgdmFyIGhleENoYXJzID0gW107XG5cdCAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2lnQnl0ZXM7IGkrKykge1xuXHQgICAgICAgICAgICAgICAgdmFyIGJpdGUgPSAod29yZHNbaSA+Pj4gMl0gPj4+ICgyNCAtIChpICUgNCkgKiA4KSkgJiAweGZmO1xuXHQgICAgICAgICAgICAgICAgaGV4Q2hhcnMucHVzaCgoYml0ZSA+Pj4gNCkudG9TdHJpbmcoMTYpKTtcblx0ICAgICAgICAgICAgICAgIGhleENoYXJzLnB1c2goKGJpdGUgJiAweDBmKS50b1N0cmluZygxNikpO1xuXHQgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgcmV0dXJuIGhleENoYXJzLmpvaW4oJycpO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDb252ZXJ0cyBhIGhleCBzdHJpbmcgdG8gYSB3b3JkIGFycmF5LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGhleFN0ciBUaGUgaGV4IHN0cmluZy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge1dvcmRBcnJheX0gVGhlIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAc3RhdGljXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciB3b3JkQXJyYXkgPSBDcnlwdG9KUy5lbmMuSGV4LnBhcnNlKGhleFN0cmluZyk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgcGFyc2U6IGZ1bmN0aW9uIChoZXhTdHIpIHtcblx0ICAgICAgICAgICAgLy8gU2hvcnRjdXRcblx0ICAgICAgICAgICAgdmFyIGhleFN0ckxlbmd0aCA9IGhleFN0ci5sZW5ndGg7XG5cblx0ICAgICAgICAgICAgLy8gQ29udmVydFxuXHQgICAgICAgICAgICB2YXIgd29yZHMgPSBbXTtcblx0ICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBoZXhTdHJMZW5ndGg7IGkgKz0gMikge1xuXHQgICAgICAgICAgICAgICAgd29yZHNbaSA+Pj4gM10gfD0gcGFyc2VJbnQoaGV4U3RyLnN1YnN0cihpLCAyKSwgMTYpIDw8ICgyNCAtIChpICUgOCkgKiA0KTtcblx0ICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgIHJldHVybiBuZXcgV29yZEFycmF5LmluaXQod29yZHMsIGhleFN0ckxlbmd0aCAvIDIpO1xuXHQgICAgICAgIH1cblx0ICAgIH07XG5cblx0ICAgIC8qKlxuXHQgICAgICogTGF0aW4xIGVuY29kaW5nIHN0cmF0ZWd5LlxuXHQgICAgICovXG5cdCAgICB2YXIgTGF0aW4xID0gQ19lbmMuTGF0aW4xID0ge1xuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIENvbnZlcnRzIGEgd29yZCBhcnJheSB0byBhIExhdGluMSBzdHJpbmcuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge1dvcmRBcnJheX0gd29yZEFycmF5IFRoZSB3b3JkIGFycmF5LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7c3RyaW5nfSBUaGUgTGF0aW4xIHN0cmluZy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBzdGF0aWNcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIGxhdGluMVN0cmluZyA9IENyeXB0b0pTLmVuYy5MYXRpbjEuc3RyaW5naWZ5KHdvcmRBcnJheSk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgc3RyaW5naWZ5OiBmdW5jdGlvbiAod29yZEFycmF5KSB7XG5cdCAgICAgICAgICAgIC8vIFNob3J0Y3V0c1xuXHQgICAgICAgICAgICB2YXIgd29yZHMgPSB3b3JkQXJyYXkud29yZHM7XG5cdCAgICAgICAgICAgIHZhciBzaWdCeXRlcyA9IHdvcmRBcnJheS5zaWdCeXRlcztcblxuXHQgICAgICAgICAgICAvLyBDb252ZXJ0XG5cdCAgICAgICAgICAgIHZhciBsYXRpbjFDaGFycyA9IFtdO1xuXHQgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNpZ0J5dGVzOyBpKyspIHtcblx0ICAgICAgICAgICAgICAgIHZhciBiaXRlID0gKHdvcmRzW2kgPj4+IDJdID4+PiAoMjQgLSAoaSAlIDQpICogOCkpICYgMHhmZjtcblx0ICAgICAgICAgICAgICAgIGxhdGluMUNoYXJzLnB1c2goU3RyaW5nLmZyb21DaGFyQ29kZShiaXRlKSk7XG5cdCAgICAgICAgICAgIH1cblxuXHQgICAgICAgICAgICByZXR1cm4gbGF0aW4xQ2hhcnMuam9pbignJyk7XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIENvbnZlcnRzIGEgTGF0aW4xIHN0cmluZyB0byBhIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gbGF0aW4xU3RyIFRoZSBMYXRpbjEgc3RyaW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7V29yZEFycmF5fSBUaGUgd29yZCBhcnJheS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBzdGF0aWNcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIHdvcmRBcnJheSA9IENyeXB0b0pTLmVuYy5MYXRpbjEucGFyc2UobGF0aW4xU3RyaW5nKTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICBwYXJzZTogZnVuY3Rpb24gKGxhdGluMVN0cikge1xuXHQgICAgICAgICAgICAvLyBTaG9ydGN1dFxuXHQgICAgICAgICAgICB2YXIgbGF0aW4xU3RyTGVuZ3RoID0gbGF0aW4xU3RyLmxlbmd0aDtcblxuXHQgICAgICAgICAgICAvLyBDb252ZXJ0XG5cdCAgICAgICAgICAgIHZhciB3b3JkcyA9IFtdO1xuXHQgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxhdGluMVN0ckxlbmd0aDsgaSsrKSB7XG5cdCAgICAgICAgICAgICAgICB3b3Jkc1tpID4+PiAyXSB8PSAobGF0aW4xU3RyLmNoYXJDb2RlQXQoaSkgJiAweGZmKSA8PCAoMjQgLSAoaSAlIDQpICogOCk7XG5cdCAgICAgICAgICAgIH1cblxuXHQgICAgICAgICAgICByZXR1cm4gbmV3IFdvcmRBcnJheS5pbml0KHdvcmRzLCBsYXRpbjFTdHJMZW5ndGgpO1xuXHQgICAgICAgIH1cblx0ICAgIH07XG5cblx0ICAgIC8qKlxuXHQgICAgICogVVRGLTggZW5jb2Rpbmcgc3RyYXRlZ3kuXG5cdCAgICAgKi9cblx0ICAgIHZhciBVdGY4ID0gQ19lbmMuVXRmOCA9IHtcblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDb252ZXJ0cyBhIHdvcmQgYXJyYXkgdG8gYSBVVEYtOCBzdHJpbmcuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge1dvcmRBcnJheX0gd29yZEFycmF5IFRoZSB3b3JkIGFycmF5LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7c3RyaW5nfSBUaGUgVVRGLTggc3RyaW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHN0YXRpY1xuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgdXRmOFN0cmluZyA9IENyeXB0b0pTLmVuYy5VdGY4LnN0cmluZ2lmeSh3b3JkQXJyYXkpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIHN0cmluZ2lmeTogZnVuY3Rpb24gKHdvcmRBcnJheSkge1xuXHQgICAgICAgICAgICB0cnkge1xuXHQgICAgICAgICAgICAgICAgcmV0dXJuIGRlY29kZVVSSUNvbXBvbmVudChlc2NhcGUoTGF0aW4xLnN0cmluZ2lmeSh3b3JkQXJyYXkpKSk7XG5cdCAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcblx0ICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTWFsZm9ybWVkIFVURi04IGRhdGEnKTtcblx0ICAgICAgICAgICAgfVxuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDb252ZXJ0cyBhIFVURi04IHN0cmluZyB0byBhIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gdXRmOFN0ciBUaGUgVVRGLTggc3RyaW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7V29yZEFycmF5fSBUaGUgd29yZCBhcnJheS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBzdGF0aWNcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIHdvcmRBcnJheSA9IENyeXB0b0pTLmVuYy5VdGY4LnBhcnNlKHV0ZjhTdHJpbmcpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIHBhcnNlOiBmdW5jdGlvbiAodXRmOFN0cikge1xuXHQgICAgICAgICAgICByZXR1cm4gTGF0aW4xLnBhcnNlKHVuZXNjYXBlKGVuY29kZVVSSUNvbXBvbmVudCh1dGY4U3RyKSkpO1xuXHQgICAgICAgIH1cblx0ICAgIH07XG5cblx0ICAgIC8qKlxuXHQgICAgICogQWJzdHJhY3QgYnVmZmVyZWQgYmxvY2sgYWxnb3JpdGhtIHRlbXBsYXRlLlxuXHQgICAgICpcblx0ICAgICAqIFRoZSBwcm9wZXJ0eSBibG9ja1NpemUgbXVzdCBiZSBpbXBsZW1lbnRlZCBpbiBhIGNvbmNyZXRlIHN1YnR5cGUuXG5cdCAgICAgKlxuXHQgICAgICogQHByb3BlcnR5IHtudW1iZXJ9IF9taW5CdWZmZXJTaXplIFRoZSBudW1iZXIgb2YgYmxvY2tzIHRoYXQgc2hvdWxkIGJlIGtlcHQgdW5wcm9jZXNzZWQgaW4gdGhlIGJ1ZmZlci4gRGVmYXVsdDogMFxuXHQgICAgICovXG5cdCAgICB2YXIgQnVmZmVyZWRCbG9ja0FsZ29yaXRobSA9IENfbGliLkJ1ZmZlcmVkQmxvY2tBbGdvcml0aG0gPSBCYXNlLmV4dGVuZCh7XG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogUmVzZXRzIHRoaXMgYmxvY2sgYWxnb3JpdGhtJ3MgZGF0YSBidWZmZXIgdG8gaXRzIGluaXRpYWwgc3RhdGUuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIGJ1ZmZlcmVkQmxvY2tBbGdvcml0aG0ucmVzZXQoKTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICByZXNldDogZnVuY3Rpb24gKCkge1xuXHQgICAgICAgICAgICAvLyBJbml0aWFsIHZhbHVlc1xuXHQgICAgICAgICAgICB0aGlzLl9kYXRhID0gbmV3IFdvcmRBcnJheS5pbml0KCk7XG5cdCAgICAgICAgICAgIHRoaXMuX25EYXRhQnl0ZXMgPSAwO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBBZGRzIG5ldyBkYXRhIHRvIHRoaXMgYmxvY2sgYWxnb3JpdGhtJ3MgYnVmZmVyLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtXb3JkQXJyYXl8c3RyaW5nfSBkYXRhIFRoZSBkYXRhIHRvIGFwcGVuZC4gU3RyaW5ncyBhcmUgY29udmVydGVkIHRvIGEgV29yZEFycmF5IHVzaW5nIFVURi04LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICBidWZmZXJlZEJsb2NrQWxnb3JpdGhtLl9hcHBlbmQoJ2RhdGEnKTtcblx0ICAgICAgICAgKiAgICAgYnVmZmVyZWRCbG9ja0FsZ29yaXRobS5fYXBwZW5kKHdvcmRBcnJheSk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgX2FwcGVuZDogZnVuY3Rpb24gKGRhdGEpIHtcblx0ICAgICAgICAgICAgLy8gQ29udmVydCBzdHJpbmcgdG8gV29yZEFycmF5LCBlbHNlIGFzc3VtZSBXb3JkQXJyYXkgYWxyZWFkeVxuXHQgICAgICAgICAgICBpZiAodHlwZW9mIGRhdGEgPT0gJ3N0cmluZycpIHtcblx0ICAgICAgICAgICAgICAgIGRhdGEgPSBVdGY4LnBhcnNlKGRhdGEpO1xuXHQgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgLy8gQXBwZW5kXG5cdCAgICAgICAgICAgIHRoaXMuX2RhdGEuY29uY2F0KGRhdGEpO1xuXHQgICAgICAgICAgICB0aGlzLl9uRGF0YUJ5dGVzICs9IGRhdGEuc2lnQnl0ZXM7XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIFByb2Nlc3NlcyBhdmFpbGFibGUgZGF0YSBibG9ja3MuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBUaGlzIG1ldGhvZCBpbnZva2VzIF9kb1Byb2Nlc3NCbG9jayhvZmZzZXQpLCB3aGljaCBtdXN0IGJlIGltcGxlbWVudGVkIGJ5IGEgY29uY3JldGUgc3VidHlwZS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gZG9GbHVzaCBXaGV0aGVyIGFsbCBibG9ja3MgYW5kIHBhcnRpYWwgYmxvY2tzIHNob3VsZCBiZSBwcm9jZXNzZWQuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtXb3JkQXJyYXl9IFRoZSBwcm9jZXNzZWQgZGF0YS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIHByb2Nlc3NlZERhdGEgPSBidWZmZXJlZEJsb2NrQWxnb3JpdGhtLl9wcm9jZXNzKCk7XG5cdCAgICAgICAgICogICAgIHZhciBwcm9jZXNzZWREYXRhID0gYnVmZmVyZWRCbG9ja0FsZ29yaXRobS5fcHJvY2VzcyghISdmbHVzaCcpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIF9wcm9jZXNzOiBmdW5jdGlvbiAoZG9GbHVzaCkge1xuXHQgICAgICAgICAgICAvLyBTaG9ydGN1dHNcblx0ICAgICAgICAgICAgdmFyIGRhdGEgPSB0aGlzLl9kYXRhO1xuXHQgICAgICAgICAgICB2YXIgZGF0YVdvcmRzID0gZGF0YS53b3Jkcztcblx0ICAgICAgICAgICAgdmFyIGRhdGFTaWdCeXRlcyA9IGRhdGEuc2lnQnl0ZXM7XG5cdCAgICAgICAgICAgIHZhciBibG9ja1NpemUgPSB0aGlzLmJsb2NrU2l6ZTtcblx0ICAgICAgICAgICAgdmFyIGJsb2NrU2l6ZUJ5dGVzID0gYmxvY2tTaXplICogNDtcblxuXHQgICAgICAgICAgICAvLyBDb3VudCBibG9ja3MgcmVhZHlcblx0ICAgICAgICAgICAgdmFyIG5CbG9ja3NSZWFkeSA9IGRhdGFTaWdCeXRlcyAvIGJsb2NrU2l6ZUJ5dGVzO1xuXHQgICAgICAgICAgICBpZiAoZG9GbHVzaCkge1xuXHQgICAgICAgICAgICAgICAgLy8gUm91bmQgdXAgdG8gaW5jbHVkZSBwYXJ0aWFsIGJsb2Nrc1xuXHQgICAgICAgICAgICAgICAgbkJsb2Nrc1JlYWR5ID0gTWF0aC5jZWlsKG5CbG9ja3NSZWFkeSk7XG5cdCAgICAgICAgICAgIH0gZWxzZSB7XG5cdCAgICAgICAgICAgICAgICAvLyBSb3VuZCBkb3duIHRvIGluY2x1ZGUgb25seSBmdWxsIGJsb2Nrcyxcblx0ICAgICAgICAgICAgICAgIC8vIGxlc3MgdGhlIG51bWJlciBvZiBibG9ja3MgdGhhdCBtdXN0IHJlbWFpbiBpbiB0aGUgYnVmZmVyXG5cdCAgICAgICAgICAgICAgICBuQmxvY2tzUmVhZHkgPSBNYXRoLm1heCgobkJsb2Nrc1JlYWR5IHwgMCkgLSB0aGlzLl9taW5CdWZmZXJTaXplLCAwKTtcblx0ICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgIC8vIENvdW50IHdvcmRzIHJlYWR5XG5cdCAgICAgICAgICAgIHZhciBuV29yZHNSZWFkeSA9IG5CbG9ja3NSZWFkeSAqIGJsb2NrU2l6ZTtcblxuXHQgICAgICAgICAgICAvLyBDb3VudCBieXRlcyByZWFkeVxuXHQgICAgICAgICAgICB2YXIgbkJ5dGVzUmVhZHkgPSBNYXRoLm1pbihuV29yZHNSZWFkeSAqIDQsIGRhdGFTaWdCeXRlcyk7XG5cblx0ICAgICAgICAgICAgLy8gUHJvY2VzcyBibG9ja3Ncblx0ICAgICAgICAgICAgaWYgKG5Xb3Jkc1JlYWR5KSB7XG5cdCAgICAgICAgICAgICAgICBmb3IgKHZhciBvZmZzZXQgPSAwOyBvZmZzZXQgPCBuV29yZHNSZWFkeTsgb2Zmc2V0ICs9IGJsb2NrU2l6ZSkge1xuXHQgICAgICAgICAgICAgICAgICAgIC8vIFBlcmZvcm0gY29uY3JldGUtYWxnb3JpdGhtIGxvZ2ljXG5cdCAgICAgICAgICAgICAgICAgICAgdGhpcy5fZG9Qcm9jZXNzQmxvY2soZGF0YVdvcmRzLCBvZmZzZXQpO1xuXHQgICAgICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgICAgICAvLyBSZW1vdmUgcHJvY2Vzc2VkIHdvcmRzXG5cdCAgICAgICAgICAgICAgICB2YXIgcHJvY2Vzc2VkV29yZHMgPSBkYXRhV29yZHMuc3BsaWNlKDAsIG5Xb3Jkc1JlYWR5KTtcblx0ICAgICAgICAgICAgICAgIGRhdGEuc2lnQnl0ZXMgLT0gbkJ5dGVzUmVhZHk7XG5cdCAgICAgICAgICAgIH1cblxuXHQgICAgICAgICAgICAvLyBSZXR1cm4gcHJvY2Vzc2VkIHdvcmRzXG5cdCAgICAgICAgICAgIHJldHVybiBuZXcgV29yZEFycmF5LmluaXQocHJvY2Vzc2VkV29yZHMsIG5CeXRlc1JlYWR5KTtcblx0ICAgICAgICB9LFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogQ3JlYXRlcyBhIGNvcHkgb2YgdGhpcyBvYmplY3QuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtPYmplY3R9IFRoZSBjbG9uZS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIGNsb25lID0gYnVmZmVyZWRCbG9ja0FsZ29yaXRobS5jbG9uZSgpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIGNsb25lOiBmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgICAgIHZhciBjbG9uZSA9IEJhc2UuY2xvbmUuY2FsbCh0aGlzKTtcblx0ICAgICAgICAgICAgY2xvbmUuX2RhdGEgPSB0aGlzLl9kYXRhLmNsb25lKCk7XG5cblx0ICAgICAgICAgICAgcmV0dXJuIGNsb25lO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICBfbWluQnVmZmVyU2l6ZTogMFxuXHQgICAgfSk7XG5cblx0ICAgIC8qKlxuXHQgICAgICogQWJzdHJhY3QgaGFzaGVyIHRlbXBsYXRlLlxuXHQgICAgICpcblx0ICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBibG9ja1NpemUgVGhlIG51bWJlciBvZiAzMi1iaXQgd29yZHMgdGhpcyBoYXNoZXIgb3BlcmF0ZXMgb24uIERlZmF1bHQ6IDE2ICg1MTIgYml0cylcblx0ICAgICAqL1xuXHQgICAgdmFyIEhhc2hlciA9IENfbGliLkhhc2hlciA9IEJ1ZmZlcmVkQmxvY2tBbGdvcml0aG0uZXh0ZW5kKHtcblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDb25maWd1cmF0aW9uIG9wdGlvbnMuXG5cdCAgICAgICAgICovXG5cdCAgICAgICAgY2ZnOiBCYXNlLmV4dGVuZCgpLFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogSW5pdGlhbGl6ZXMgYSBuZXdseSBjcmVhdGVkIGhhc2hlci5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBjZmcgKE9wdGlvbmFsKSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIHVzZSBmb3IgdGhpcyBoYXNoIGNvbXB1dGF0aW9uLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgaGFzaGVyID0gQ3J5cHRvSlMuYWxnby5TSEEyNTYuY3JlYXRlKCk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgaW5pdDogZnVuY3Rpb24gKGNmZykge1xuXHQgICAgICAgICAgICAvLyBBcHBseSBjb25maWcgZGVmYXVsdHNcblx0ICAgICAgICAgICAgdGhpcy5jZmcgPSB0aGlzLmNmZy5leHRlbmQoY2ZnKTtcblxuXHQgICAgICAgICAgICAvLyBTZXQgaW5pdGlhbCB2YWx1ZXNcblx0ICAgICAgICAgICAgdGhpcy5yZXNldCgpO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBSZXNldHMgdGhpcyBoYXNoZXIgdG8gaXRzIGluaXRpYWwgc3RhdGUuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIGhhc2hlci5yZXNldCgpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIHJlc2V0OiBmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgICAgIC8vIFJlc2V0IGRhdGEgYnVmZmVyXG5cdCAgICAgICAgICAgIEJ1ZmZlcmVkQmxvY2tBbGdvcml0aG0ucmVzZXQuY2FsbCh0aGlzKTtcblxuXHQgICAgICAgICAgICAvLyBQZXJmb3JtIGNvbmNyZXRlLWhhc2hlciBsb2dpY1xuXHQgICAgICAgICAgICB0aGlzLl9kb1Jlc2V0KCk7XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIFVwZGF0ZXMgdGhpcyBoYXNoZXIgd2l0aCBhIG1lc3NhZ2UuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge1dvcmRBcnJheXxzdHJpbmd9IG1lc3NhZ2VVcGRhdGUgVGhlIG1lc3NhZ2UgdG8gYXBwZW5kLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7SGFzaGVyfSBUaGlzIGhhc2hlci5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgaGFzaGVyLnVwZGF0ZSgnbWVzc2FnZScpO1xuXHQgICAgICAgICAqICAgICBoYXNoZXIudXBkYXRlKHdvcmRBcnJheSk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgdXBkYXRlOiBmdW5jdGlvbiAobWVzc2FnZVVwZGF0ZSkge1xuXHQgICAgICAgICAgICAvLyBBcHBlbmRcblx0ICAgICAgICAgICAgdGhpcy5fYXBwZW5kKG1lc3NhZ2VVcGRhdGUpO1xuXG5cdCAgICAgICAgICAgIC8vIFVwZGF0ZSB0aGUgaGFzaFxuXHQgICAgICAgICAgICB0aGlzLl9wcm9jZXNzKCk7XG5cblx0ICAgICAgICAgICAgLy8gQ2hhaW5hYmxlXG5cdCAgICAgICAgICAgIHJldHVybiB0aGlzO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBGaW5hbGl6ZXMgdGhlIGhhc2ggY29tcHV0YXRpb24uXG5cdCAgICAgICAgICogTm90ZSB0aGF0IHRoZSBmaW5hbGl6ZSBvcGVyYXRpb24gaXMgZWZmZWN0aXZlbHkgYSBkZXN0cnVjdGl2ZSwgcmVhZC1vbmNlIG9wZXJhdGlvbi5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7V29yZEFycmF5fHN0cmluZ30gbWVzc2FnZVVwZGF0ZSAoT3B0aW9uYWwpIEEgZmluYWwgbWVzc2FnZSB1cGRhdGUuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtXb3JkQXJyYXl9IFRoZSBoYXNoLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgaGFzaCA9IGhhc2hlci5maW5hbGl6ZSgpO1xuXHQgICAgICAgICAqICAgICB2YXIgaGFzaCA9IGhhc2hlci5maW5hbGl6ZSgnbWVzc2FnZScpO1xuXHQgICAgICAgICAqICAgICB2YXIgaGFzaCA9IGhhc2hlci5maW5hbGl6ZSh3b3JkQXJyYXkpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIGZpbmFsaXplOiBmdW5jdGlvbiAobWVzc2FnZVVwZGF0ZSkge1xuXHQgICAgICAgICAgICAvLyBGaW5hbCBtZXNzYWdlIHVwZGF0ZVxuXHQgICAgICAgICAgICBpZiAobWVzc2FnZVVwZGF0ZSkge1xuXHQgICAgICAgICAgICAgICAgdGhpcy5fYXBwZW5kKG1lc3NhZ2VVcGRhdGUpO1xuXHQgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgLy8gUGVyZm9ybSBjb25jcmV0ZS1oYXNoZXIgbG9naWNcblx0ICAgICAgICAgICAgdmFyIGhhc2ggPSB0aGlzLl9kb0ZpbmFsaXplKCk7XG5cblx0ICAgICAgICAgICAgcmV0dXJuIGhhc2g7XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIGJsb2NrU2l6ZTogNTEyLzMyLFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogQ3JlYXRlcyBhIHNob3J0Y3V0IGZ1bmN0aW9uIHRvIGEgaGFzaGVyJ3Mgb2JqZWN0IGludGVyZmFjZS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7SGFzaGVyfSBoYXNoZXIgVGhlIGhhc2hlciB0byBjcmVhdGUgYSBoZWxwZXIgZm9yLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7RnVuY3Rpb259IFRoZSBzaG9ydGN1dCBmdW5jdGlvbi5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBzdGF0aWNcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIFNIQTI1NiA9IENyeXB0b0pTLmxpYi5IYXNoZXIuX2NyZWF0ZUhlbHBlcihDcnlwdG9KUy5hbGdvLlNIQTI1Nik7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgX2NyZWF0ZUhlbHBlcjogZnVuY3Rpb24gKGhhc2hlcikge1xuXHQgICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24gKG1lc3NhZ2UsIGNmZykge1xuXHQgICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBoYXNoZXIuaW5pdChjZmcpLmZpbmFsaXplKG1lc3NhZ2UpO1xuXHQgICAgICAgICAgICB9O1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDcmVhdGVzIGEgc2hvcnRjdXQgZnVuY3Rpb24gdG8gdGhlIEhNQUMncyBvYmplY3QgaW50ZXJmYWNlLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtIYXNoZXJ9IGhhc2hlciBUaGUgaGFzaGVyIHRvIHVzZSBpbiB0aGlzIEhNQUMgaGVscGVyLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7RnVuY3Rpb259IFRoZSBzaG9ydGN1dCBmdW5jdGlvbi5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBzdGF0aWNcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIEhtYWNTSEEyNTYgPSBDcnlwdG9KUy5saWIuSGFzaGVyLl9jcmVhdGVIbWFjSGVscGVyKENyeXB0b0pTLmFsZ28uU0hBMjU2KTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICBfY3JlYXRlSG1hY0hlbHBlcjogZnVuY3Rpb24gKGhhc2hlcikge1xuXHQgICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24gKG1lc3NhZ2UsIGtleSkge1xuXHQgICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBDX2FsZ28uSE1BQy5pbml0KGhhc2hlciwga2V5KS5maW5hbGl6ZShtZXNzYWdlKTtcblx0ICAgICAgICAgICAgfTtcblx0ICAgICAgICB9XG5cdCAgICB9KTtcblxuXHQgICAgLyoqXG5cdCAgICAgKiBBbGdvcml0aG0gbmFtZXNwYWNlLlxuXHQgICAgICovXG5cdCAgICB2YXIgQ19hbGdvID0gQy5hbGdvID0ge307XG5cblx0ICAgIHJldHVybiBDO1xuXHR9KE1hdGgpKTtcblxuXG5cdHJldHVybiBDcnlwdG9KUztcblxufSkpOyIsIjsoZnVuY3Rpb24gKHJvb3QsIGZhY3RvcnksIHVuZGVmKSB7XG5cdGlmICh0eXBlb2YgZXhwb3J0cyA9PT0gXCJvYmplY3RcIikge1xuXHRcdC8vIENvbW1vbkpTXG5cdFx0bW9kdWxlLmV4cG9ydHMgPSBleHBvcnRzID0gZmFjdG9yeShyZXF1aXJlKFwiLi9jb3JlXCIpLCByZXF1aXJlKFwiLi94NjQtY29yZVwiKSk7XG5cdH1cblx0ZWxzZSBpZiAodHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIGRlZmluZS5hbWQpIHtcblx0XHQvLyBBTURcblx0XHRkZWZpbmUoW1wiLi9jb3JlXCIsIFwiLi94NjQtY29yZVwiXSwgZmFjdG9yeSk7XG5cdH1cblx0ZWxzZSB7XG5cdFx0Ly8gR2xvYmFsIChicm93c2VyKVxuXHRcdGZhY3Rvcnkocm9vdC5DcnlwdG9KUyk7XG5cdH1cbn0odGhpcywgZnVuY3Rpb24gKENyeXB0b0pTKSB7XG5cblx0KGZ1bmN0aW9uIChNYXRoKSB7XG5cdCAgICAvLyBTaG9ydGN1dHNcblx0ICAgIHZhciBDID0gQ3J5cHRvSlM7XG5cdCAgICB2YXIgQ19saWIgPSBDLmxpYjtcblx0ICAgIHZhciBXb3JkQXJyYXkgPSBDX2xpYi5Xb3JkQXJyYXk7XG5cdCAgICB2YXIgSGFzaGVyID0gQ19saWIuSGFzaGVyO1xuXHQgICAgdmFyIENfeDY0ID0gQy54NjQ7XG5cdCAgICB2YXIgWDY0V29yZCA9IENfeDY0LldvcmQ7XG5cdCAgICB2YXIgQ19hbGdvID0gQy5hbGdvO1xuXG5cdCAgICAvLyBDb25zdGFudHMgdGFibGVzXG5cdCAgICB2YXIgUkhPX09GRlNFVFMgPSBbXTtcblx0ICAgIHZhciBQSV9JTkRFWEVTICA9IFtdO1xuXHQgICAgdmFyIFJPVU5EX0NPTlNUQU5UUyA9IFtdO1xuXG5cdCAgICAvLyBDb21wdXRlIENvbnN0YW50c1xuXHQgICAgKGZ1bmN0aW9uICgpIHtcblx0ICAgICAgICAvLyBDb21wdXRlIHJobyBvZmZzZXQgY29uc3RhbnRzXG5cdCAgICAgICAgdmFyIHggPSAxLCB5ID0gMDtcblx0ICAgICAgICBmb3IgKHZhciB0ID0gMDsgdCA8IDI0OyB0KyspIHtcblx0ICAgICAgICAgICAgUkhPX09GRlNFVFNbeCArIDUgKiB5XSA9ICgodCArIDEpICogKHQgKyAyKSAvIDIpICUgNjQ7XG5cblx0ICAgICAgICAgICAgdmFyIG5ld1ggPSB5ICUgNTtcblx0ICAgICAgICAgICAgdmFyIG5ld1kgPSAoMiAqIHggKyAzICogeSkgJSA1O1xuXHQgICAgICAgICAgICB4ID0gbmV3WDtcblx0ICAgICAgICAgICAgeSA9IG5ld1k7XG5cdCAgICAgICAgfVxuXG5cdCAgICAgICAgLy8gQ29tcHV0ZSBwaSBpbmRleCBjb25zdGFudHNcblx0ICAgICAgICBmb3IgKHZhciB4ID0gMDsgeCA8IDU7IHgrKykge1xuXHQgICAgICAgICAgICBmb3IgKHZhciB5ID0gMDsgeSA8IDU7IHkrKykge1xuXHQgICAgICAgICAgICAgICAgUElfSU5ERVhFU1t4ICsgNSAqIHldID0geSArICgoMiAqIHggKyAzICogeSkgJSA1KSAqIDU7XG5cdCAgICAgICAgICAgIH1cblx0ICAgICAgICB9XG5cblx0ICAgICAgICAvLyBDb21wdXRlIHJvdW5kIGNvbnN0YW50c1xuXHQgICAgICAgIHZhciBMRlNSID0gMHgwMTtcblx0ICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IDI0OyBpKyspIHtcblx0ICAgICAgICAgICAgdmFyIHJvdW5kQ29uc3RhbnRNc3cgPSAwO1xuXHQgICAgICAgICAgICB2YXIgcm91bmRDb25zdGFudExzdyA9IDA7XG5cblx0ICAgICAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCA3OyBqKyspIHtcblx0ICAgICAgICAgICAgICAgIGlmIChMRlNSICYgMHgwMSkge1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciBiaXRQb3NpdGlvbiA9ICgxIDw8IGopIC0gMTtcblx0ICAgICAgICAgICAgICAgICAgICBpZiAoYml0UG9zaXRpb24gPCAzMikge1xuXHQgICAgICAgICAgICAgICAgICAgICAgICByb3VuZENvbnN0YW50THN3IF49IDEgPDwgYml0UG9zaXRpb247XG5cdCAgICAgICAgICAgICAgICAgICAgfSBlbHNlIC8qIGlmIChiaXRQb3NpdGlvbiA+PSAzMikgKi8ge1xuXHQgICAgICAgICAgICAgICAgICAgICAgICByb3VuZENvbnN0YW50TXN3IF49IDEgPDwgKGJpdFBvc2l0aW9uIC0gMzIpO1xuXHQgICAgICAgICAgICAgICAgICAgIH1cblx0ICAgICAgICAgICAgICAgIH1cblxuXHQgICAgICAgICAgICAgICAgLy8gQ29tcHV0ZSBuZXh0IExGU1Jcblx0ICAgICAgICAgICAgICAgIGlmIChMRlNSICYgMHg4MCkge1xuXHQgICAgICAgICAgICAgICAgICAgIC8vIFByaW1pdGl2ZSBwb2x5bm9taWFsIG92ZXIgR0YoMik6IHheOCArIHheNiArIHheNSArIHheNCArIDFcblx0ICAgICAgICAgICAgICAgICAgICBMRlNSID0gKExGU1IgPDwgMSkgXiAweDcxO1xuXHQgICAgICAgICAgICAgICAgfSBlbHNlIHtcblx0ICAgICAgICAgICAgICAgICAgICBMRlNSIDw8PSAxO1xuXHQgICAgICAgICAgICAgICAgfVxuXHQgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgUk9VTkRfQ09OU1RBTlRTW2ldID0gWDY0V29yZC5jcmVhdGUocm91bmRDb25zdGFudE1zdywgcm91bmRDb25zdGFudExzdyk7XG5cdCAgICAgICAgfVxuXHQgICAgfSgpKTtcblxuXHQgICAgLy8gUmV1c2FibGUgb2JqZWN0cyBmb3IgdGVtcG9yYXJ5IHZhbHVlc1xuXHQgICAgdmFyIFQgPSBbXTtcblx0ICAgIChmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCAyNTsgaSsrKSB7XG5cdCAgICAgICAgICAgIFRbaV0gPSBYNjRXb3JkLmNyZWF0ZSgpO1xuXHQgICAgICAgIH1cblx0ICAgIH0oKSk7XG5cblx0ICAgIC8qKlxuXHQgICAgICogU0hBLTMgaGFzaCBhbGdvcml0aG0uXG5cdCAgICAgKi9cblx0ICAgIHZhciBTSEEzID0gQ19hbGdvLlNIQTMgPSBIYXNoZXIuZXh0ZW5kKHtcblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDb25maWd1cmF0aW9uIG9wdGlvbnMuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcHJvcGVydHkge251bWJlcn0gb3V0cHV0TGVuZ3RoXG5cdCAgICAgICAgICogICBUaGUgZGVzaXJlZCBudW1iZXIgb2YgYml0cyBpbiB0aGUgb3V0cHV0IGhhc2guXG5cdCAgICAgICAgICogICBPbmx5IHZhbHVlcyBwZXJtaXR0ZWQgYXJlOiAyMjQsIDI1NiwgMzg0LCA1MTIuXG5cdCAgICAgICAgICogICBEZWZhdWx0OiA1MTJcblx0ICAgICAgICAgKi9cblx0ICAgICAgICBjZmc6IEhhc2hlci5jZmcuZXh0ZW5kKHtcblx0ICAgICAgICAgICAgb3V0cHV0TGVuZ3RoOiA1MTJcblx0ICAgICAgICB9KSxcblxuXHQgICAgICAgIF9kb1Jlc2V0OiBmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgICAgIHZhciBzdGF0ZSA9IHRoaXMuX3N0YXRlID0gW11cblx0ICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCAyNTsgaSsrKSB7XG5cdCAgICAgICAgICAgICAgICBzdGF0ZVtpXSA9IG5ldyBYNjRXb3JkLmluaXQoKTtcblx0ICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgIHRoaXMuYmxvY2tTaXplID0gKDE2MDAgLSAyICogdGhpcy5jZmcub3V0cHV0TGVuZ3RoKSAvIDMyO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICBfZG9Qcm9jZXNzQmxvY2s6IGZ1bmN0aW9uIChNLCBvZmZzZXQpIHtcblx0ICAgICAgICAgICAgLy8gU2hvcnRjdXRzXG5cdCAgICAgICAgICAgIHZhciBzdGF0ZSA9IHRoaXMuX3N0YXRlO1xuXHQgICAgICAgICAgICB2YXIgbkJsb2NrU2l6ZUxhbmVzID0gdGhpcy5ibG9ja1NpemUgLyAyO1xuXG5cdCAgICAgICAgICAgIC8vIEFic29yYlxuXHQgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG5CbG9ja1NpemVMYW5lczsgaSsrKSB7XG5cdCAgICAgICAgICAgICAgICAvLyBTaG9ydGN1dHNcblx0ICAgICAgICAgICAgICAgIHZhciBNMmkgID0gTVtvZmZzZXQgKyAyICogaV07XG5cdCAgICAgICAgICAgICAgICB2YXIgTTJpMSA9IE1bb2Zmc2V0ICsgMiAqIGkgKyAxXTtcblxuXHQgICAgICAgICAgICAgICAgLy8gU3dhcCBlbmRpYW5cblx0ICAgICAgICAgICAgICAgIE0yaSA9IChcblx0ICAgICAgICAgICAgICAgICAgICAoKChNMmkgPDwgOCkgIHwgKE0yaSA+Pj4gMjQpKSAmIDB4MDBmZjAwZmYpIHxcblx0ICAgICAgICAgICAgICAgICAgICAoKChNMmkgPDwgMjQpIHwgKE0yaSA+Pj4gOCkpICAmIDB4ZmYwMGZmMDApXG5cdCAgICAgICAgICAgICAgICApO1xuXHQgICAgICAgICAgICAgICAgTTJpMSA9IChcblx0ICAgICAgICAgICAgICAgICAgICAoKChNMmkxIDw8IDgpICB8IChNMmkxID4+PiAyNCkpICYgMHgwMGZmMDBmZikgfFxuXHQgICAgICAgICAgICAgICAgICAgICgoKE0yaTEgPDwgMjQpIHwgKE0yaTEgPj4+IDgpKSAgJiAweGZmMDBmZjAwKVxuXHQgICAgICAgICAgICAgICAgKTtcblxuXHQgICAgICAgICAgICAgICAgLy8gQWJzb3JiIG1lc3NhZ2UgaW50byBzdGF0ZVxuXHQgICAgICAgICAgICAgICAgdmFyIGxhbmUgPSBzdGF0ZVtpXTtcblx0ICAgICAgICAgICAgICAgIGxhbmUuaGlnaCBePSBNMmkxO1xuXHQgICAgICAgICAgICAgICAgbGFuZS5sb3cgIF49IE0yaTtcblx0ICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgIC8vIFJvdW5kc1xuXHQgICAgICAgICAgICBmb3IgKHZhciByb3VuZCA9IDA7IHJvdW5kIDwgMjQ7IHJvdW5kKyspIHtcblx0ICAgICAgICAgICAgICAgIC8vIFRoZXRhXG5cdCAgICAgICAgICAgICAgICBmb3IgKHZhciB4ID0gMDsgeCA8IDU7IHgrKykge1xuXHQgICAgICAgICAgICAgICAgICAgIC8vIE1peCBjb2x1bW4gbGFuZXNcblx0ICAgICAgICAgICAgICAgICAgICB2YXIgdE1zdyA9IDAsIHRMc3cgPSAwO1xuXHQgICAgICAgICAgICAgICAgICAgIGZvciAodmFyIHkgPSAwOyB5IDwgNTsgeSsrKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIHZhciBsYW5lID0gc3RhdGVbeCArIDUgKiB5XTtcblx0ICAgICAgICAgICAgICAgICAgICAgICAgdE1zdyBePSBsYW5lLmhpZ2g7XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIHRMc3cgXj0gbGFuZS5sb3c7XG5cdCAgICAgICAgICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgICAgICAgICAgLy8gVGVtcG9yYXJ5IHZhbHVlc1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciBUeCA9IFRbeF07XG5cdCAgICAgICAgICAgICAgICAgICAgVHguaGlnaCA9IHRNc3c7XG5cdCAgICAgICAgICAgICAgICAgICAgVHgubG93ICA9IHRMc3c7XG5cdCAgICAgICAgICAgICAgICB9XG5cdCAgICAgICAgICAgICAgICBmb3IgKHZhciB4ID0gMDsgeCA8IDU7IHgrKykge1xuXHQgICAgICAgICAgICAgICAgICAgIC8vIFNob3J0Y3V0c1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciBUeDQgPSBUWyh4ICsgNCkgJSA1XTtcblx0ICAgICAgICAgICAgICAgICAgICB2YXIgVHgxID0gVFsoeCArIDEpICUgNV07XG5cdCAgICAgICAgICAgICAgICAgICAgdmFyIFR4MU1zdyA9IFR4MS5oaWdoO1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciBUeDFMc3cgPSBUeDEubG93O1xuXG5cdCAgICAgICAgICAgICAgICAgICAgLy8gTWl4IHN1cnJvdW5kaW5nIGNvbHVtbnNcblx0ICAgICAgICAgICAgICAgICAgICB2YXIgdE1zdyA9IFR4NC5oaWdoIF4gKChUeDFNc3cgPDwgMSkgfCAoVHgxTHN3ID4+PiAzMSkpO1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciB0THN3ID0gVHg0LmxvdyAgXiAoKFR4MUxzdyA8PCAxKSB8IChUeDFNc3cgPj4+IDMxKSk7XG5cdCAgICAgICAgICAgICAgICAgICAgZm9yICh2YXIgeSA9IDA7IHkgPCA1OyB5KyspIHtcblx0ICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGxhbmUgPSBzdGF0ZVt4ICsgNSAqIHldO1xuXHQgICAgICAgICAgICAgICAgICAgICAgICBsYW5lLmhpZ2ggXj0gdE1zdztcblx0ICAgICAgICAgICAgICAgICAgICAgICAgbGFuZS5sb3cgIF49IHRMc3c7XG5cdCAgICAgICAgICAgICAgICAgICAgfVxuXHQgICAgICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgICAgICAvLyBSaG8gUGlcblx0ICAgICAgICAgICAgICAgIGZvciAodmFyIGxhbmVJbmRleCA9IDE7IGxhbmVJbmRleCA8IDI1OyBsYW5lSW5kZXgrKykge1xuXHQgICAgICAgICAgICAgICAgICAgIC8vIFNob3J0Y3V0c1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciBsYW5lID0gc3RhdGVbbGFuZUluZGV4XTtcblx0ICAgICAgICAgICAgICAgICAgICB2YXIgbGFuZU1zdyA9IGxhbmUuaGlnaDtcblx0ICAgICAgICAgICAgICAgICAgICB2YXIgbGFuZUxzdyA9IGxhbmUubG93O1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciByaG9PZmZzZXQgPSBSSE9fT0ZGU0VUU1tsYW5lSW5kZXhdO1xuXG5cdCAgICAgICAgICAgICAgICAgICAgLy8gUm90YXRlIGxhbmVzXG5cdCAgICAgICAgICAgICAgICAgICAgaWYgKHJob09mZnNldCA8IDMyKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIHZhciB0TXN3ID0gKGxhbmVNc3cgPDwgcmhvT2Zmc2V0KSB8IChsYW5lTHN3ID4+PiAoMzIgLSByaG9PZmZzZXQpKTtcblx0ICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHRMc3cgPSAobGFuZUxzdyA8PCByaG9PZmZzZXQpIHwgKGxhbmVNc3cgPj4+ICgzMiAtIHJob09mZnNldCkpO1xuXHQgICAgICAgICAgICAgICAgICAgIH0gZWxzZSAvKiBpZiAocmhvT2Zmc2V0ID49IDMyKSAqLyB7XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIHZhciB0TXN3ID0gKGxhbmVMc3cgPDwgKHJob09mZnNldCAtIDMyKSkgfCAobGFuZU1zdyA+Pj4gKDY0IC0gcmhvT2Zmc2V0KSk7XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIHZhciB0THN3ID0gKGxhbmVNc3cgPDwgKHJob09mZnNldCAtIDMyKSkgfCAobGFuZUxzdyA+Pj4gKDY0IC0gcmhvT2Zmc2V0KSk7XG5cdCAgICAgICAgICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgICAgICAgICAgLy8gVHJhbnNwb3NlIGxhbmVzXG5cdCAgICAgICAgICAgICAgICAgICAgdmFyIFRQaUxhbmUgPSBUW1BJX0lOREVYRVNbbGFuZUluZGV4XV07XG5cdCAgICAgICAgICAgICAgICAgICAgVFBpTGFuZS5oaWdoID0gdE1zdztcblx0ICAgICAgICAgICAgICAgICAgICBUUGlMYW5lLmxvdyAgPSB0THN3O1xuXHQgICAgICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgICAgICAvLyBSaG8gcGkgYXQgeCA9IHkgPSAwXG5cdCAgICAgICAgICAgICAgICB2YXIgVDAgPSBUWzBdO1xuXHQgICAgICAgICAgICAgICAgdmFyIHN0YXRlMCA9IHN0YXRlWzBdO1xuXHQgICAgICAgICAgICAgICAgVDAuaGlnaCA9IHN0YXRlMC5oaWdoO1xuXHQgICAgICAgICAgICAgICAgVDAubG93ICA9IHN0YXRlMC5sb3c7XG5cblx0ICAgICAgICAgICAgICAgIC8vIENoaVxuXHQgICAgICAgICAgICAgICAgZm9yICh2YXIgeCA9IDA7IHggPCA1OyB4KyspIHtcblx0ICAgICAgICAgICAgICAgICAgICBmb3IgKHZhciB5ID0gMDsgeSA8IDU7IHkrKykge1xuXHQgICAgICAgICAgICAgICAgICAgICAgICAvLyBTaG9ydGN1dHNcblx0ICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGxhbmVJbmRleCA9IHggKyA1ICogeTtcblx0ICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGxhbmUgPSBzdGF0ZVtsYW5lSW5kZXhdO1xuXHQgICAgICAgICAgICAgICAgICAgICAgICB2YXIgVExhbmUgPSBUW2xhbmVJbmRleF07XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIHZhciBUeDFMYW5lID0gVFsoKHggKyAxKSAlIDUpICsgNSAqIHldO1xuXHQgICAgICAgICAgICAgICAgICAgICAgICB2YXIgVHgyTGFuZSA9IFRbKCh4ICsgMikgJSA1KSArIDUgKiB5XTtcblxuXHQgICAgICAgICAgICAgICAgICAgICAgICAvLyBNaXggcm93c1xuXHQgICAgICAgICAgICAgICAgICAgICAgICBsYW5lLmhpZ2ggPSBUTGFuZS5oaWdoIF4gKH5UeDFMYW5lLmhpZ2ggJiBUeDJMYW5lLmhpZ2gpO1xuXHQgICAgICAgICAgICAgICAgICAgICAgICBsYW5lLmxvdyAgPSBUTGFuZS5sb3cgIF4gKH5UeDFMYW5lLmxvdyAgJiBUeDJMYW5lLmxvdyk7XG5cdCAgICAgICAgICAgICAgICAgICAgfVxuXHQgICAgICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgICAgICAvLyBJb3RhXG5cdCAgICAgICAgICAgICAgICB2YXIgbGFuZSA9IHN0YXRlWzBdO1xuXHQgICAgICAgICAgICAgICAgdmFyIHJvdW5kQ29uc3RhbnQgPSBST1VORF9DT05TVEFOVFNbcm91bmRdO1xuXHQgICAgICAgICAgICAgICAgbGFuZS5oaWdoIF49IHJvdW5kQ29uc3RhbnQuaGlnaDtcblx0ICAgICAgICAgICAgICAgIGxhbmUubG93ICBePSByb3VuZENvbnN0YW50Lmxvdzs7XG5cdCAgICAgICAgICAgIH1cblx0ICAgICAgICB9LFxuXG5cdCAgICAgICAgX2RvRmluYWxpemU6IGZ1bmN0aW9uICgpIHtcblx0ICAgICAgICAgICAgLy8gU2hvcnRjdXRzXG5cdCAgICAgICAgICAgIHZhciBkYXRhID0gdGhpcy5fZGF0YTtcblx0ICAgICAgICAgICAgdmFyIGRhdGFXb3JkcyA9IGRhdGEud29yZHM7XG5cdCAgICAgICAgICAgIHZhciBuQml0c1RvdGFsID0gdGhpcy5fbkRhdGFCeXRlcyAqIDg7XG5cdCAgICAgICAgICAgIHZhciBuQml0c0xlZnQgPSBkYXRhLnNpZ0J5dGVzICogODtcblx0ICAgICAgICAgICAgdmFyIGJsb2NrU2l6ZUJpdHMgPSB0aGlzLmJsb2NrU2l6ZSAqIDMyO1xuXG5cdCAgICAgICAgICAgIC8vIEFkZCBwYWRkaW5nXG5cdCAgICAgICAgICAgIGRhdGFXb3Jkc1tuQml0c0xlZnQgPj4+IDVdIHw9IDB4MSA8PCAoMjQgLSBuQml0c0xlZnQgJSAzMik7XG5cdCAgICAgICAgICAgIGRhdGFXb3Jkc1soKE1hdGguY2VpbCgobkJpdHNMZWZ0ICsgMSkgLyBibG9ja1NpemVCaXRzKSAqIGJsb2NrU2l6ZUJpdHMpID4+PiA1KSAtIDFdIHw9IDB4ODA7XG5cdCAgICAgICAgICAgIGRhdGEuc2lnQnl0ZXMgPSBkYXRhV29yZHMubGVuZ3RoICogNDtcblxuXHQgICAgICAgICAgICAvLyBIYXNoIGZpbmFsIGJsb2Nrc1xuXHQgICAgICAgICAgICB0aGlzLl9wcm9jZXNzKCk7XG5cblx0ICAgICAgICAgICAgLy8gU2hvcnRjdXRzXG5cdCAgICAgICAgICAgIHZhciBzdGF0ZSA9IHRoaXMuX3N0YXRlO1xuXHQgICAgICAgICAgICB2YXIgb3V0cHV0TGVuZ3RoQnl0ZXMgPSB0aGlzLmNmZy5vdXRwdXRMZW5ndGggLyA4O1xuXHQgICAgICAgICAgICB2YXIgb3V0cHV0TGVuZ3RoTGFuZXMgPSBvdXRwdXRMZW5ndGhCeXRlcyAvIDg7XG5cblx0ICAgICAgICAgICAgLy8gU3F1ZWV6ZVxuXHQgICAgICAgICAgICB2YXIgaGFzaFdvcmRzID0gW107XG5cdCAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgb3V0cHV0TGVuZ3RoTGFuZXM7IGkrKykge1xuXHQgICAgICAgICAgICAgICAgLy8gU2hvcnRjdXRzXG5cdCAgICAgICAgICAgICAgICB2YXIgbGFuZSA9IHN0YXRlW2ldO1xuXHQgICAgICAgICAgICAgICAgdmFyIGxhbmVNc3cgPSBsYW5lLmhpZ2g7XG5cdCAgICAgICAgICAgICAgICB2YXIgbGFuZUxzdyA9IGxhbmUubG93O1xuXG5cdCAgICAgICAgICAgICAgICAvLyBTd2FwIGVuZGlhblxuXHQgICAgICAgICAgICAgICAgbGFuZU1zdyA9IChcblx0ICAgICAgICAgICAgICAgICAgICAoKChsYW5lTXN3IDw8IDgpICB8IChsYW5lTXN3ID4+PiAyNCkpICYgMHgwMGZmMDBmZikgfFxuXHQgICAgICAgICAgICAgICAgICAgICgoKGxhbmVNc3cgPDwgMjQpIHwgKGxhbmVNc3cgPj4+IDgpKSAgJiAweGZmMDBmZjAwKVxuXHQgICAgICAgICAgICAgICAgKTtcblx0ICAgICAgICAgICAgICAgIGxhbmVMc3cgPSAoXG5cdCAgICAgICAgICAgICAgICAgICAgKCgobGFuZUxzdyA8PCA4KSAgfCAobGFuZUxzdyA+Pj4gMjQpKSAmIDB4MDBmZjAwZmYpIHxcblx0ICAgICAgICAgICAgICAgICAgICAoKChsYW5lTHN3IDw8IDI0KSB8IChsYW5lTHN3ID4+PiA4KSkgICYgMHhmZjAwZmYwMClcblx0ICAgICAgICAgICAgICAgICk7XG5cblx0ICAgICAgICAgICAgICAgIC8vIFNxdWVlemUgc3RhdGUgdG8gcmV0cmlldmUgaGFzaFxuXHQgICAgICAgICAgICAgICAgaGFzaFdvcmRzLnB1c2gobGFuZUxzdyk7XG5cdCAgICAgICAgICAgICAgICBoYXNoV29yZHMucHVzaChsYW5lTXN3KTtcblx0ICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgIC8vIFJldHVybiBmaW5hbCBjb21wdXRlZCBoYXNoXG5cdCAgICAgICAgICAgIHJldHVybiBuZXcgV29yZEFycmF5LmluaXQoaGFzaFdvcmRzLCBvdXRwdXRMZW5ndGhCeXRlcyk7XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIGNsb25lOiBmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgICAgIHZhciBjbG9uZSA9IEhhc2hlci5jbG9uZS5jYWxsKHRoaXMpO1xuXG5cdCAgICAgICAgICAgIHZhciBzdGF0ZSA9IGNsb25lLl9zdGF0ZSA9IHRoaXMuX3N0YXRlLnNsaWNlKDApO1xuXHQgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IDI1OyBpKyspIHtcblx0ICAgICAgICAgICAgICAgIHN0YXRlW2ldID0gc3RhdGVbaV0uY2xvbmUoKTtcblx0ICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgIHJldHVybiBjbG9uZTtcblx0ICAgICAgICB9XG5cdCAgICB9KTtcblxuXHQgICAgLyoqXG5cdCAgICAgKiBTaG9ydGN1dCBmdW5jdGlvbiB0byB0aGUgaGFzaGVyJ3Mgb2JqZWN0IGludGVyZmFjZS5cblx0ICAgICAqXG5cdCAgICAgKiBAcGFyYW0ge1dvcmRBcnJheXxzdHJpbmd9IG1lc3NhZ2UgVGhlIG1lc3NhZ2UgdG8gaGFzaC5cblx0ICAgICAqXG5cdCAgICAgKiBAcmV0dXJuIHtXb3JkQXJyYXl9IFRoZSBoYXNoLlxuXHQgICAgICpcblx0ICAgICAqIEBzdGF0aWNcblx0ICAgICAqXG5cdCAgICAgKiBAZXhhbXBsZVxuXHQgICAgICpcblx0ICAgICAqICAgICB2YXIgaGFzaCA9IENyeXB0b0pTLlNIQTMoJ21lc3NhZ2UnKTtcblx0ICAgICAqICAgICB2YXIgaGFzaCA9IENyeXB0b0pTLlNIQTMod29yZEFycmF5KTtcblx0ICAgICAqL1xuXHQgICAgQy5TSEEzID0gSGFzaGVyLl9jcmVhdGVIZWxwZXIoU0hBMyk7XG5cblx0ICAgIC8qKlxuXHQgICAgICogU2hvcnRjdXQgZnVuY3Rpb24gdG8gdGhlIEhNQUMncyBvYmplY3QgaW50ZXJmYWNlLlxuXHQgICAgICpcblx0ICAgICAqIEBwYXJhbSB7V29yZEFycmF5fHN0cmluZ30gbWVzc2FnZSBUaGUgbWVzc2FnZSB0byBoYXNoLlxuXHQgICAgICogQHBhcmFtIHtXb3JkQXJyYXl8c3RyaW5nfSBrZXkgVGhlIHNlY3JldCBrZXkuXG5cdCAgICAgKlxuXHQgICAgICogQHJldHVybiB7V29yZEFycmF5fSBUaGUgSE1BQy5cblx0ICAgICAqXG5cdCAgICAgKiBAc3RhdGljXG5cdCAgICAgKlxuXHQgICAgICogQGV4YW1wbGVcblx0ICAgICAqXG5cdCAgICAgKiAgICAgdmFyIGhtYWMgPSBDcnlwdG9KUy5IbWFjU0hBMyhtZXNzYWdlLCBrZXkpO1xuXHQgICAgICovXG5cdCAgICBDLkhtYWNTSEEzID0gSGFzaGVyLl9jcmVhdGVIbWFjSGVscGVyKFNIQTMpO1xuXHR9KE1hdGgpKTtcblxuXG5cdHJldHVybiBDcnlwdG9KUy5TSEEzO1xuXG59KSk7IiwiOyhmdW5jdGlvbiAocm9vdCwgZmFjdG9yeSkge1xuXHRpZiAodHlwZW9mIGV4cG9ydHMgPT09IFwib2JqZWN0XCIpIHtcblx0XHQvLyBDb21tb25KU1xuXHRcdG1vZHVsZS5leHBvcnRzID0gZXhwb3J0cyA9IGZhY3RvcnkocmVxdWlyZShcIi4vY29yZVwiKSk7XG5cdH1cblx0ZWxzZSBpZiAodHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIGRlZmluZS5hbWQpIHtcblx0XHQvLyBBTURcblx0XHRkZWZpbmUoW1wiLi9jb3JlXCJdLCBmYWN0b3J5KTtcblx0fVxuXHRlbHNlIHtcblx0XHQvLyBHbG9iYWwgKGJyb3dzZXIpXG5cdFx0ZmFjdG9yeShyb290LkNyeXB0b0pTKTtcblx0fVxufSh0aGlzLCBmdW5jdGlvbiAoQ3J5cHRvSlMpIHtcblxuXHQoZnVuY3Rpb24gKHVuZGVmaW5lZCkge1xuXHQgICAgLy8gU2hvcnRjdXRzXG5cdCAgICB2YXIgQyA9IENyeXB0b0pTO1xuXHQgICAgdmFyIENfbGliID0gQy5saWI7XG5cdCAgICB2YXIgQmFzZSA9IENfbGliLkJhc2U7XG5cdCAgICB2YXIgWDMyV29yZEFycmF5ID0gQ19saWIuV29yZEFycmF5O1xuXG5cdCAgICAvKipcblx0ICAgICAqIHg2NCBuYW1lc3BhY2UuXG5cdCAgICAgKi9cblx0ICAgIHZhciBDX3g2NCA9IEMueDY0ID0ge307XG5cblx0ICAgIC8qKlxuXHQgICAgICogQSA2NC1iaXQgd29yZC5cblx0ICAgICAqL1xuXHQgICAgdmFyIFg2NFdvcmQgPSBDX3g2NC5Xb3JkID0gQmFzZS5leHRlbmQoe1xuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIEluaXRpYWxpemVzIGEgbmV3bHkgY3JlYXRlZCA2NC1iaXQgd29yZC5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBoaWdoIFRoZSBoaWdoIDMyIGJpdHMuXG5cdCAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGxvdyBUaGUgbG93IDMyIGJpdHMuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciB4NjRXb3JkID0gQ3J5cHRvSlMueDY0LldvcmQuY3JlYXRlKDB4MDAwMTAyMDMsIDB4MDQwNTA2MDcpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIGluaXQ6IGZ1bmN0aW9uIChoaWdoLCBsb3cpIHtcblx0ICAgICAgICAgICAgdGhpcy5oaWdoID0gaGlnaDtcblx0ICAgICAgICAgICAgdGhpcy5sb3cgPSBsb3c7XG5cdCAgICAgICAgfVxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogQml0d2lzZSBOT1RzIHRoaXMgd29yZC5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge1g2NFdvcmR9IEEgbmV3IHg2NC1Xb3JkIG9iamVjdCBhZnRlciBuZWdhdGluZy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIG5lZ2F0ZWQgPSB4NjRXb3JkLm5vdCgpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIC8vIG5vdDogZnVuY3Rpb24gKCkge1xuXHQgICAgICAgICAgICAvLyB2YXIgaGlnaCA9IH50aGlzLmhpZ2g7XG5cdCAgICAgICAgICAgIC8vIHZhciBsb3cgPSB+dGhpcy5sb3c7XG5cblx0ICAgICAgICAgICAgLy8gcmV0dXJuIFg2NFdvcmQuY3JlYXRlKGhpZ2gsIGxvdyk7XG5cdCAgICAgICAgLy8gfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIEJpdHdpc2UgQU5EcyB0aGlzIHdvcmQgd2l0aCB0aGUgcGFzc2VkIHdvcmQuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge1g2NFdvcmR9IHdvcmQgVGhlIHg2NC1Xb3JkIHRvIEFORCB3aXRoIHRoaXMgd29yZC5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge1g2NFdvcmR9IEEgbmV3IHg2NC1Xb3JkIG9iamVjdCBhZnRlciBBTkRpbmcuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciBhbmRlZCA9IHg2NFdvcmQuYW5kKGFub3RoZXJYNjRXb3JkKTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICAvLyBhbmQ6IGZ1bmN0aW9uICh3b3JkKSB7XG5cdCAgICAgICAgICAgIC8vIHZhciBoaWdoID0gdGhpcy5oaWdoICYgd29yZC5oaWdoO1xuXHQgICAgICAgICAgICAvLyB2YXIgbG93ID0gdGhpcy5sb3cgJiB3b3JkLmxvdztcblxuXHQgICAgICAgICAgICAvLyByZXR1cm4gWDY0V29yZC5jcmVhdGUoaGlnaCwgbG93KTtcblx0ICAgICAgICAvLyB9LFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogQml0d2lzZSBPUnMgdGhpcyB3b3JkIHdpdGggdGhlIHBhc3NlZCB3b3JkLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtYNjRXb3JkfSB3b3JkIFRoZSB4NjQtV29yZCB0byBPUiB3aXRoIHRoaXMgd29yZC5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge1g2NFdvcmR9IEEgbmV3IHg2NC1Xb3JkIG9iamVjdCBhZnRlciBPUmluZy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIG9yZWQgPSB4NjRXb3JkLm9yKGFub3RoZXJYNjRXb3JkKTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICAvLyBvcjogZnVuY3Rpb24gKHdvcmQpIHtcblx0ICAgICAgICAgICAgLy8gdmFyIGhpZ2ggPSB0aGlzLmhpZ2ggfCB3b3JkLmhpZ2g7XG5cdCAgICAgICAgICAgIC8vIHZhciBsb3cgPSB0aGlzLmxvdyB8IHdvcmQubG93O1xuXG5cdCAgICAgICAgICAgIC8vIHJldHVybiBYNjRXb3JkLmNyZWF0ZShoaWdoLCBsb3cpO1xuXHQgICAgICAgIC8vIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBCaXR3aXNlIFhPUnMgdGhpcyB3b3JkIHdpdGggdGhlIHBhc3NlZCB3b3JkLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtYNjRXb3JkfSB3b3JkIFRoZSB4NjQtV29yZCB0byBYT1Igd2l0aCB0aGlzIHdvcmQuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtYNjRXb3JkfSBBIG5ldyB4NjQtV29yZCBvYmplY3QgYWZ0ZXIgWE9SaW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgeG9yZWQgPSB4NjRXb3JkLnhvcihhbm90aGVyWDY0V29yZCk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgLy8geG9yOiBmdW5jdGlvbiAod29yZCkge1xuXHQgICAgICAgICAgICAvLyB2YXIgaGlnaCA9IHRoaXMuaGlnaCBeIHdvcmQuaGlnaDtcblx0ICAgICAgICAgICAgLy8gdmFyIGxvdyA9IHRoaXMubG93IF4gd29yZC5sb3c7XG5cblx0ICAgICAgICAgICAgLy8gcmV0dXJuIFg2NFdvcmQuY3JlYXRlKGhpZ2gsIGxvdyk7XG5cdCAgICAgICAgLy8gfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIFNoaWZ0cyB0aGlzIHdvcmQgbiBiaXRzIHRvIHRoZSBsZWZ0LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IG4gVGhlIG51bWJlciBvZiBiaXRzIHRvIHNoaWZ0LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7WDY0V29yZH0gQSBuZXcgeDY0LVdvcmQgb2JqZWN0IGFmdGVyIHNoaWZ0aW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgc2hpZnRlZCA9IHg2NFdvcmQuc2hpZnRMKDI1KTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICAvLyBzaGlmdEw6IGZ1bmN0aW9uIChuKSB7XG5cdCAgICAgICAgICAgIC8vIGlmIChuIDwgMzIpIHtcblx0ICAgICAgICAgICAgICAgIC8vIHZhciBoaWdoID0gKHRoaXMuaGlnaCA8PCBuKSB8ICh0aGlzLmxvdyA+Pj4gKDMyIC0gbikpO1xuXHQgICAgICAgICAgICAgICAgLy8gdmFyIGxvdyA9IHRoaXMubG93IDw8IG47XG5cdCAgICAgICAgICAgIC8vIH0gZWxzZSB7XG5cdCAgICAgICAgICAgICAgICAvLyB2YXIgaGlnaCA9IHRoaXMubG93IDw8IChuIC0gMzIpO1xuXHQgICAgICAgICAgICAgICAgLy8gdmFyIGxvdyA9IDA7XG5cdCAgICAgICAgICAgIC8vIH1cblxuXHQgICAgICAgICAgICAvLyByZXR1cm4gWDY0V29yZC5jcmVhdGUoaGlnaCwgbG93KTtcblx0ICAgICAgICAvLyB9LFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogU2hpZnRzIHRoaXMgd29yZCBuIGJpdHMgdG8gdGhlIHJpZ2h0LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IG4gVGhlIG51bWJlciBvZiBiaXRzIHRvIHNoaWZ0LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7WDY0V29yZH0gQSBuZXcgeDY0LVdvcmQgb2JqZWN0IGFmdGVyIHNoaWZ0aW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgc2hpZnRlZCA9IHg2NFdvcmQuc2hpZnRSKDcpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIC8vIHNoaWZ0UjogZnVuY3Rpb24gKG4pIHtcblx0ICAgICAgICAgICAgLy8gaWYgKG4gPCAzMikge1xuXHQgICAgICAgICAgICAgICAgLy8gdmFyIGxvdyA9ICh0aGlzLmxvdyA+Pj4gbikgfCAodGhpcy5oaWdoIDw8ICgzMiAtIG4pKTtcblx0ICAgICAgICAgICAgICAgIC8vIHZhciBoaWdoID0gdGhpcy5oaWdoID4+PiBuO1xuXHQgICAgICAgICAgICAvLyB9IGVsc2Uge1xuXHQgICAgICAgICAgICAgICAgLy8gdmFyIGxvdyA9IHRoaXMuaGlnaCA+Pj4gKG4gLSAzMik7XG5cdCAgICAgICAgICAgICAgICAvLyB2YXIgaGlnaCA9IDA7XG5cdCAgICAgICAgICAgIC8vIH1cblxuXHQgICAgICAgICAgICAvLyByZXR1cm4gWDY0V29yZC5jcmVhdGUoaGlnaCwgbG93KTtcblx0ICAgICAgICAvLyB9LFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogUm90YXRlcyB0aGlzIHdvcmQgbiBiaXRzIHRvIHRoZSBsZWZ0LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IG4gVGhlIG51bWJlciBvZiBiaXRzIHRvIHJvdGF0ZS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge1g2NFdvcmR9IEEgbmV3IHg2NC1Xb3JkIG9iamVjdCBhZnRlciByb3RhdGluZy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIHJvdGF0ZWQgPSB4NjRXb3JkLnJvdEwoMjUpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIC8vIHJvdEw6IGZ1bmN0aW9uIChuKSB7XG5cdCAgICAgICAgICAgIC8vIHJldHVybiB0aGlzLnNoaWZ0TChuKS5vcih0aGlzLnNoaWZ0Uig2NCAtIG4pKTtcblx0ICAgICAgICAvLyB9LFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogUm90YXRlcyB0aGlzIHdvcmQgbiBiaXRzIHRvIHRoZSByaWdodC5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBuIFRoZSBudW1iZXIgb2YgYml0cyB0byByb3RhdGUuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtYNjRXb3JkfSBBIG5ldyB4NjQtV29yZCBvYmplY3QgYWZ0ZXIgcm90YXRpbmcuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciByb3RhdGVkID0geDY0V29yZC5yb3RSKDcpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIC8vIHJvdFI6IGZ1bmN0aW9uIChuKSB7XG5cdCAgICAgICAgICAgIC8vIHJldHVybiB0aGlzLnNoaWZ0UihuKS5vcih0aGlzLnNoaWZ0TCg2NCAtIG4pKTtcblx0ICAgICAgICAvLyB9LFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogQWRkcyB0aGlzIHdvcmQgd2l0aCB0aGUgcGFzc2VkIHdvcmQuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge1g2NFdvcmR9IHdvcmQgVGhlIHg2NC1Xb3JkIHRvIGFkZCB3aXRoIHRoaXMgd29yZC5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge1g2NFdvcmR9IEEgbmV3IHg2NC1Xb3JkIG9iamVjdCBhZnRlciBhZGRpbmcuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciBhZGRlZCA9IHg2NFdvcmQuYWRkKGFub3RoZXJYNjRXb3JkKTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICAvLyBhZGQ6IGZ1bmN0aW9uICh3b3JkKSB7XG5cdCAgICAgICAgICAgIC8vIHZhciBsb3cgPSAodGhpcy5sb3cgKyB3b3JkLmxvdykgfCAwO1xuXHQgICAgICAgICAgICAvLyB2YXIgY2FycnkgPSAobG93ID4+PiAwKSA8ICh0aGlzLmxvdyA+Pj4gMCkgPyAxIDogMDtcblx0ICAgICAgICAgICAgLy8gdmFyIGhpZ2ggPSAodGhpcy5oaWdoICsgd29yZC5oaWdoICsgY2FycnkpIHwgMDtcblxuXHQgICAgICAgICAgICAvLyByZXR1cm4gWDY0V29yZC5jcmVhdGUoaGlnaCwgbG93KTtcblx0ICAgICAgICAvLyB9XG5cdCAgICB9KTtcblxuXHQgICAgLyoqXG5cdCAgICAgKiBBbiBhcnJheSBvZiA2NC1iaXQgd29yZHMuXG5cdCAgICAgKlxuXHQgICAgICogQHByb3BlcnR5IHtBcnJheX0gd29yZHMgVGhlIGFycmF5IG9mIENyeXB0b0pTLng2NC5Xb3JkIG9iamVjdHMuXG5cdCAgICAgKiBAcHJvcGVydHkge251bWJlcn0gc2lnQnl0ZXMgVGhlIG51bWJlciBvZiBzaWduaWZpY2FudCBieXRlcyBpbiB0aGlzIHdvcmQgYXJyYXkuXG5cdCAgICAgKi9cblx0ICAgIHZhciBYNjRXb3JkQXJyYXkgPSBDX3g2NC5Xb3JkQXJyYXkgPSBCYXNlLmV4dGVuZCh7XG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogSW5pdGlhbGl6ZXMgYSBuZXdseSBjcmVhdGVkIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge0FycmF5fSB3b3JkcyAoT3B0aW9uYWwpIEFuIGFycmF5IG9mIENyeXB0b0pTLng2NC5Xb3JkIG9iamVjdHMuXG5cdCAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHNpZ0J5dGVzIChPcHRpb25hbCkgVGhlIG51bWJlciBvZiBzaWduaWZpY2FudCBieXRlcyBpbiB0aGUgd29yZHMuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciB3b3JkQXJyYXkgPSBDcnlwdG9KUy54NjQuV29yZEFycmF5LmNyZWF0ZSgpO1xuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciB3b3JkQXJyYXkgPSBDcnlwdG9KUy54NjQuV29yZEFycmF5LmNyZWF0ZShbXG5cdCAgICAgICAgICogICAgICAgICBDcnlwdG9KUy54NjQuV29yZC5jcmVhdGUoMHgwMDAxMDIwMywgMHgwNDA1MDYwNyksXG5cdCAgICAgICAgICogICAgICAgICBDcnlwdG9KUy54NjQuV29yZC5jcmVhdGUoMHgxODE5MWExYiwgMHgxYzFkMWUxZilcblx0ICAgICAgICAgKiAgICAgXSk7XG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIHdvcmRBcnJheSA9IENyeXB0b0pTLng2NC5Xb3JkQXJyYXkuY3JlYXRlKFtcblx0ICAgICAgICAgKiAgICAgICAgIENyeXB0b0pTLng2NC5Xb3JkLmNyZWF0ZSgweDAwMDEwMjAzLCAweDA0MDUwNjA3KSxcblx0ICAgICAgICAgKiAgICAgICAgIENyeXB0b0pTLng2NC5Xb3JkLmNyZWF0ZSgweDE4MTkxYTFiLCAweDFjMWQxZTFmKVxuXHQgICAgICAgICAqICAgICBdLCAxMCk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgaW5pdDogZnVuY3Rpb24gKHdvcmRzLCBzaWdCeXRlcykge1xuXHQgICAgICAgICAgICB3b3JkcyA9IHRoaXMud29yZHMgPSB3b3JkcyB8fCBbXTtcblxuXHQgICAgICAgICAgICBpZiAoc2lnQnl0ZXMgIT0gdW5kZWZpbmVkKSB7XG5cdCAgICAgICAgICAgICAgICB0aGlzLnNpZ0J5dGVzID0gc2lnQnl0ZXM7XG5cdCAgICAgICAgICAgIH0gZWxzZSB7XG5cdCAgICAgICAgICAgICAgICB0aGlzLnNpZ0J5dGVzID0gd29yZHMubGVuZ3RoICogODtcblx0ICAgICAgICAgICAgfVxuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDb252ZXJ0cyB0aGlzIDY0LWJpdCB3b3JkIGFycmF5IHRvIGEgMzItYml0IHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtDcnlwdG9KUy5saWIuV29yZEFycmF5fSBUaGlzIHdvcmQgYXJyYXkncyBkYXRhIGFzIGEgMzItYml0IHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciB4MzJXb3JkQXJyYXkgPSB4NjRXb3JkQXJyYXkudG9YMzIoKTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICB0b1gzMjogZnVuY3Rpb24gKCkge1xuXHQgICAgICAgICAgICAvLyBTaG9ydGN1dHNcblx0ICAgICAgICAgICAgdmFyIHg2NFdvcmRzID0gdGhpcy53b3Jkcztcblx0ICAgICAgICAgICAgdmFyIHg2NFdvcmRzTGVuZ3RoID0geDY0V29yZHMubGVuZ3RoO1xuXG5cdCAgICAgICAgICAgIC8vIENvbnZlcnRcblx0ICAgICAgICAgICAgdmFyIHgzMldvcmRzID0gW107XG5cdCAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgeDY0V29yZHNMZW5ndGg7IGkrKykge1xuXHQgICAgICAgICAgICAgICAgdmFyIHg2NFdvcmQgPSB4NjRXb3Jkc1tpXTtcblx0ICAgICAgICAgICAgICAgIHgzMldvcmRzLnB1c2goeDY0V29yZC5oaWdoKTtcblx0ICAgICAgICAgICAgICAgIHgzMldvcmRzLnB1c2goeDY0V29yZC5sb3cpO1xuXHQgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgcmV0dXJuIFgzMldvcmRBcnJheS5jcmVhdGUoeDMyV29yZHMsIHRoaXMuc2lnQnl0ZXMpO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDcmVhdGVzIGEgY29weSBvZiB0aGlzIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtYNjRXb3JkQXJyYXl9IFRoZSBjbG9uZS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIGNsb25lID0geDY0V29yZEFycmF5LmNsb25lKCk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgY2xvbmU6IGZ1bmN0aW9uICgpIHtcblx0ICAgICAgICAgICAgdmFyIGNsb25lID0gQmFzZS5jbG9uZS5jYWxsKHRoaXMpO1xuXG5cdCAgICAgICAgICAgIC8vIENsb25lIFwid29yZHNcIiBhcnJheVxuXHQgICAgICAgICAgICB2YXIgd29yZHMgPSBjbG9uZS53b3JkcyA9IHRoaXMud29yZHMuc2xpY2UoMCk7XG5cblx0ICAgICAgICAgICAgLy8gQ2xvbmUgZWFjaCBYNjRXb3JkIG9iamVjdFxuXHQgICAgICAgICAgICB2YXIgd29yZHNMZW5ndGggPSB3b3Jkcy5sZW5ndGg7XG5cdCAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgd29yZHNMZW5ndGg7IGkrKykge1xuXHQgICAgICAgICAgICAgICAgd29yZHNbaV0gPSB3b3Jkc1tpXS5jbG9uZSgpO1xuXHQgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgcmV0dXJuIGNsb25lO1xuXHQgICAgICAgIH1cblx0ICAgIH0pO1xuXHR9KCkpO1xuXG5cblx0cmV0dXJuIENyeXB0b0pTO1xuXG59KSk7IiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEJpZ051bWJlcjsgLy8ganNoaW50IGlnbm9yZTpsaW5lXG5cbiIsInZhciB3ZWIzID0gcmVxdWlyZSgnLi9saWIvd2ViMycpO1xud2ViMy5wcm92aWRlcnMuSHR0cFByb3ZpZGVyID0gcmVxdWlyZSgnLi9saWIvd2ViMy9odHRwcHJvdmlkZXInKTtcbndlYjMucHJvdmlkZXJzLlF0U3luY1Byb3ZpZGVyID0gcmVxdWlyZSgnLi9saWIvd2ViMy9xdHN5bmMnKTtcbndlYjMuZXRoLmNvbnRyYWN0ID0gcmVxdWlyZSgnLi9saWIvd2ViMy9jb250cmFjdCcpO1xud2ViMy5ldGgubmFtZXJlZyA9IHJlcXVpcmUoJy4vbGliL3dlYjMvbmFtZXJlZycpO1xud2ViMy5ldGguc2VuZElCQU5UcmFuc2FjdGlvbiA9IHJlcXVpcmUoJy4vbGliL3dlYjMvdHJhbnNmZXInKTtcblxuLy8gZG9udCBvdmVycmlkZSBnbG9iYWwgdmFyaWFibGVcbmlmICh0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyAmJiB0eXBlb2Ygd2luZG93LndlYjMgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgd2luZG93LndlYjMgPSB3ZWIzO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHdlYjM7XG5cbiJdfQ== diff --git a/libjsqrc/ethereumjs/dist/web3-light.min.js b/libjsqrc/ethereumjs/dist/web3-light.min.js deleted file mode 100644 index ea9ef2bba..000000000 --- a/libjsqrc/ethereumjs/dist/web3-light.min.js +++ /dev/null @@ -1,2 +0,0 @@ -require=function t(e,n,r){function o(a,s){if(!n[a]){if(!e[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(i)return i(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var p=n[a]={exports:{}};e[a][0].call(p.exports,function(t){var n=e[a][1][t];return o(n?n:t)},p,p.exports,t,e,n,r)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;ai;i+=64)n.push(this._outputFormatter(new a(t.dynamicPart().substr(i+64,64))));return n}return this._outputFormatter(t)},u.prototype.sliceParam=function(t,e,n){return"bytes"===this._mode?a.decodeBytes(t,e):s(n)?a.decodeArray(t,e):a.decodeParam(t,e)};var c=function(t){this._types=t};c.prototype._requireType=function(t){var e=this._types.filter(function(e){return e.isType(t)})[0];if(!e)throw Error("invalid solidity type!: "+t);return e},c.prototype._formatInput=function(t,e){return this._requireType(t).formatInput(e,s(t))},c.prototype.encodeParam=function(t,e){return this._formatInput(t,e).encode()},c.prototype.encodeParams=function(t,e){var n=this,r=t.map(function(t,r){return n._formatInput(t,e[r])});return a.encodeList(r)},c.prototype.decodeParam=function(t,e){return this.decodeParams([t],e)[0]},c.prototype.decodeParams=function(t,e){var n=this;return t.map(function(t,r){var o=n._requireType(t),i=o.sliceParam(e,r,t);return o.formatOutput(i,s(t))})};var p=new c([new u({name:"address",match:"strict",mode:"value",inputFormatter:i.formatInputInt,outputFormatter:i.formatOutputAddress}),new u({name:"bool",match:"strict",mode:"value",inputFormatter:i.formatInputBool,outputFormatter:i.formatOutputBool}),new u({name:"int",match:"prefix",mode:"value",inputFormatter:i.formatInputInt,outputFormatter:i.formatOutputInt}),new u({name:"uint",match:"prefix",mode:"value",inputFormatter:i.formatInputInt,outputFormatter:i.formatOutputUInt}),new u({name:"bytes",match:"strict",mode:"bytes",inputFormatter:i.formatInputDynamicBytes,outputFormatter:i.formatOutputDynamicBytes}),new u({name:"bytes",match:"prefix",mode:"value",inputFormatter:i.formatInputBytes,outputFormatter:i.formatOutputBytes}),new u({name:"real",match:"prefix",mode:"value",inputFormatter:i.formatInputReal,outputFormatter:i.formatOutputReal}),new u({name:"ureal",match:"prefix",mode:"value",inputFormatter:i.formatInputReal,outputFormatter:i.formatOutputUReal})]);e.exports=p},{"../utils/utils":7,"./formatters":2,"./param":3,"bignumber.js":"bignumber.js"}],2:[function(t,e,n){var r=t("bignumber.js"),o=t("../utils/utils"),i=t("../utils/config"),a=t("./param"),s=function(t){var e=2*i.ETH_PADDING;r.config(i.ETH_BIGNUMBER_ROUNDING_MODE);var n=o.padLeft(o.toTwosComplement(t).round().toString(16),e);return new a(n)},u=function(t){var e=o.fromAscii(t,i.ETH_PADDING).substr(2);return new a(e)},c=function(t){var e=o.fromAscii(t,i.ETH_PADDING).substr(2);return new a(s(t.length).value+e,32)},p=function(t){var e="000000000000000000000000000000000000000000000000000000000000000"+(t?"1":"0");return new a(e)},l=function(t){return s(new r(t).times(new r(2).pow(128)))},f=function(t){return"1"===new r(t.substr(0,1),16).toString(2).substr(0,1)},m=function(t){var e=t.staticPart()||"0";return f(e)?new r(e,16).minus(new r("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",16)).minus(1):new r(e,16)},h=function(t){var e=t.staticPart()||"0";return new r(e,16)},d=function(t){return m(t).dividedBy(new r(2).pow(128))},y=function(t){return h(t).dividedBy(new r(2).pow(128))},g=function(t){return"0000000000000000000000000000000000000000000000000000000000000001"===t.staticPart()?!0:!1},v=function(t){return o.toAscii(t.staticPart())},b=function(t){return o.toAscii(t.dynamicPart().slice(64))},w=function(t){var e=t.staticPart();return"0x"+e.slice(e.length-40,e.length)};e.exports={formatInputInt:s,formatInputBytes:u,formatInputDynamicBytes:c,formatInputBool:p,formatInputReal:l,formatOutputInt:m,formatOutputUInt:h,formatOutputReal:d,formatOutputUReal:y,formatOutputBool:g,formatOutputBytes:v,formatOutputDynamicBytes:b,formatOutputAddress:w}},{"../utils/config":5,"../utils/utils":7,"./param":3,"bignumber.js":"bignumber.js"}],3:[function(t,e,n){var r=t("../utils/utils"),o=function(t,e){this.value=t||"",this.offset=e};o.prototype.dynamicPartLength=function(){return this.dynamicPart().length/2},o.prototype.withOffset=function(t){return new o(this.value,t)},o.prototype.combine=function(t){return new o(this.value+t.value)},o.prototype.isDynamic=function(){return this.value.length>64||void 0!==this.offset},o.prototype.offsetAsBytes=function(){return this.isDynamic()?r.padLeft(r.toTwosComplement(this.offset).toString(16),64):""},o.prototype.staticPart=function(){return this.isDynamic()?this.offsetAsBytes():this.value},o.prototype.dynamicPart=function(){return this.isDynamic()?this.value:""},o.prototype.encode=function(){return this.staticPart()+this.dynamicPart()},o.encodeList=function(t){var e=32*t.length,n=t.map(function(t){if(!t.isDynamic())return t;var n=e;return e+=t.dynamicPartLength(),t.withOffset(n)});return n.reduce(function(t,e){return t+e.dynamicPart()},n.reduce(function(t,e){return t+e.staticPart()},""))},o.decodeParam=function(t,e){return e=e||0,new o(t.substr(64*e,64))};var i=function(t,e){return parseInt("0x"+t.substr(64*e,64))};o.decodeBytes=function(t,e){e=e||0;var n=i(t,e);return new o(t.substr(2*n,128),0)},o.decodeArray=function(t,e){e=e||0;var n=i(t,e),r=parseInt("0x"+t.substr(2*n,64));return new o(t.substr(2*n,64*(r+1)),0)},e.exports=o},{"../utils/utils":7}],4:[function(t,e,n){"use strict";n.XMLHttpRequest="undefined"==typeof XMLHttpRequest?{}:XMLHttpRequest},{}],5:[function(t,e,n){var r=t("bignumber.js"),o=["wei","kwei","Mwei","Gwei","szabo","finney","femtoether","picoether","nanoether","microether","milliether","nano","micro","milli","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:o,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:r.ROUND_DOWN},ETH_POLLING_TIMEOUT:1e3,defaultBlock:"latest",defaultAccount:void 0}},{"bignumber.js":"bignumber.js"}],6:[function(t,e,n){var r=t("./utils"),o=t("crypto-js/sha3");e.exports=function(t,e){return"0x"!==t.substr(0,2)||e||(console.warn("requirement of using web3.fromAscii before sha3 is deprecated"),console.warn("new usage: 'web3.sha3(\"hello\")'"),console.warn("see https://github.com/ethereum/web3.js/pull/205"),console.warn("if you need to hash hex value, you can do 'sha3(\"0xfff\", true)'"),t=r.toAscii(t)),o(t,{outputLength:256}).toString()}},{"./utils":7,"crypto-js/sha3":33}],7:[function(t,e,n){var r=t("bignumber.js"),o={wei:"1",kwei:"1000",ada:"1000",femtoether:"1000",mwei:"1000000",babbage:"1000000",picoether:"1000000",gwei:"1000000000",shannon:"1000000000",nanoether:"1000000000",nano:"1000000000",szabo:"1000000000000",microether:"1000000000000",micro:"1000000000000",finney:"1000000000000000",milliether:"1000000000000000",milli:"1000000000000000",ether:"1000000000000000000",kether:"1000000000000000000000",grand:"1000000000000000000000",einstein:"1000000000000000000000",mether:"1000000000000000000000000",gether:"1000000000000000000000000000",tether:"1000000000000000000000000000000"},i=function(t,e,n){return new Array(e-t.length+1).join(n?n:"0")+t},a=function(t){var e="",n=0,r=t.length;for("0x"===t.substring(0,2)&&(n=2);r>n;n+=2){var o=parseInt(t.substr(n,2),16);if(0===o)break;e+=String.fromCharCode(o)}return e},s=function(t){for(var e="",n=0;nthis._inputTypes.length&&i.isObject(t[t.length-1])&&(e=t[t.length-1]),e.to=this._address,e.data="0x"+this.signature()+o.encodeParams(this._inputTypes,t),e},s.prototype.signature=function(){return a(this._name).slice(0,8)},s.prototype.unpackOutput=function(t){if(t){t=t.length>=2?t.slice(2):t;var e=o.decodeParams(this._outputTypes,t);return 1===e.length?e[0]:e}},s.prototype.call=function(){var t=Array.prototype.slice.call(arguments).filter(function(t){return void 0!==t}),e=this.extractCallback(t),n=this.toPayload(t);if(!e){var o=r.eth.call(n);return this.unpackOutput(o)}var i=this;r.eth.call(n,function(t,n){e(t,i.unpackOutput(n))})},s.prototype.sendTransaction=function(){var t=Array.prototype.slice.call(arguments).filter(function(t){return void 0!==t}),e=this.extractCallback(t),n=this.toPayload(t);return e?void r.eth.sendTransaction(n,e):r.eth.sendTransaction(n)},s.prototype.estimateGas=function(){var t=Array.prototype.slice.call(arguments),e=this.extractCallback(t),n=this.toPayload(t);return e?void r.eth.estimateGas(n,e):r.eth.estimateGas(n)},s.prototype.displayName=function(){return i.extractDisplayName(this._name)},s.prototype.typeName=function(){return i.extractTypeName(this._name)},s.prototype.request=function(){var t=Array.prototype.slice.call(arguments),e=this.extractCallback(t),n=this.toPayload(t),r=this.unpackOutput.bind(this);return{callback:e,payload:n,format:r}},s.prototype.execute=function(){var t=!this._constant;return t?this.sendTransaction.apply(this,Array.prototype.slice.call(arguments)):this.call.apply(this,Array.prototype.slice.call(arguments))},s.prototype.attachToContract=function(t){var e=this.execute.bind(this);e.request=this.request.bind(this),e.call=this.call.bind(this),e.sendTransaction=this.sendTransaction.bind(this),e.estimateGas=this.estimateGas.bind(this);var n=this.displayName();t[n]||(t[n]=e),t[n][this.typeName()]=e},e.exports=s},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9}],19:[function(t,e,n){"use strict";var r=t("xmlhttprequest").XMLHttpRequest,o=t("./errors"),i=function(t){this.host=t||"http://localhost:8545"};i.prototype.send=function(t){var e=new r;e.open("POST",this.host,!1);try{e.send(JSON.stringify(t))}catch(n){throw o.InvalidConnection(this.host)}var i=e.responseText;try{i=JSON.parse(i)}catch(a){throw o.InvalidResponse(i)}return i},i.prototype.sendAsync=function(t,e){var n=new r;n.onreadystatechange=function(){if(4===n.readyState){var t=n.responseText,r=null;try{t=JSON.parse(t)}catch(i){r=o.InvalidResponse(t)}e(r,t)}},n.open("POST",this.host,!0);try{n.send(JSON.stringify(t))}catch(i){e(o.InvalidConnection(this.host))}},e.exports=i},{"./errors":13,xmlhttprequest:4}],20:[function(t,e,n){var r=t("../utils/utils"),o=function(t){this._iban=t};o.prototype.isValid=function(){return r.isIBAN(this._iban)},o.prototype.isDirect=function(){return 34===this._iban.length},o.prototype.isIndirect=function(){return 20===this._iban.length},o.prototype.checksum=function(){return this._iban.substr(2,2)},o.prototype.institution=function(){return this.isIndirect()?this._iban.substr(7,4):""},o.prototype.client=function(){return this.isIndirect()?this._iban.substr(11):""},o.prototype.address=function(){return this.isDirect()?this._iban.substr(4):""},e.exports=o},{"../utils/utils":7}],21:[function(t,e,n){var r=function(){return arguments.callee._singletonInstance?arguments.callee._singletonInstance:(arguments.callee._singletonInstance=this,void(this.messageId=1))};r.getInstance=function(){var t=new r;return t},r.prototype.toPayload=function(t,e){return t||console.error("jsonrpc method should be specified!"),{jsonrpc:"2.0",method:t,params:e||[],id:this.messageId++}},r.prototype.isValidResponse=function(t){return!!t&&!t.error&&"2.0"===t.jsonrpc&&"number"==typeof t.id&&void 0!==t.result},r.prototype.toBatchPayload=function(t){var e=this;return t.map(function(t){return e.toPayload(t.method,t.params)})},e.exports=r},{}],22:[function(t,e,n){var r=t("./requestmanager"),o=t("../utils/utils"),i=t("./errors"),a=function(t){this.name=t.name,this.call=t.call,this.params=t.params||0,this.inputFormatter=t.inputFormatter,this.outputFormatter=t.outputFormatter};a.prototype.getCall=function(t){return o.isFunction(this.call)?this.call(t):this.call},a.prototype.extractCallback=function(t){return o.isFunction(t[t.length-1])?t.pop():void 0},a.prototype.validateArgs=function(t){if(t.length!==this.params)throw i.InvalidNumberOfParams()},a.prototype.formatInput=function(t){return this.inputFormatter?this.inputFormatter.map(function(e,n){return e?e(t[n]):t[n]}):t},a.prototype.formatOutput=function(t){return this.outputFormatter&&null!==t?this.outputFormatter(t):t},a.prototype.attachToObject=function(t){var e=this.send.bind(this);e.request=this.request.bind(this),e.call=this.call;var n=this.name.split(".");n.length>1?(t[n[0]]=t[n[0]]||{},t[n[0]][n[1]]=e):t[n[0]]=e},a.prototype.toPayload=function(t){var e=this.getCall(t),n=this.extractCallback(t),r=this.formatInput(t);return this.validateArgs(r),{method:e,params:r,callback:n}},a.prototype.request=function(){var t=this.toPayload(Array.prototype.slice.call(arguments));return t.format=this.formatOutput.bind(this),t},a.prototype.send=function(){var t=this.toPayload(Array.prototype.slice.call(arguments));if(t.callback){var e=this;return r.getInstance().sendAsync(t,function(n,r){t.callback(n,e.formatOutput(r))})}return this.formatOutput(r.getInstance().send(t))},e.exports=a},{"../utils/utils":7,"./errors":13,"./requestmanager":27}],23:[function(t,e,n){var r=t("./contract"),o="0xc6d9d2cd449a754c494264e1809c50e34d64562b",i=[{constant:!0,inputs:[{name:"_owner",type:"address"}],name:"name",outputs:[{name:"o_name",type:"bytes32"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"owner",outputs:[{name:"",type:"address"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"content",outputs:[{name:"",type:"bytes32"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"addr",outputs:[{name:"",type:"address"}],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"}],name:"reserve",outputs:[],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"subRegistrar",outputs:[{name:"o_subRegistrar",type:"address"}],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_newOwner",type:"address"}],name:"transfer",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_registrar",type:"address"}],name:"setSubRegistrar",outputs:[],type:"function"},{constant:!1,inputs:[],name:"Registrar",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_a",type:"address"},{name:"_primary",type:"bool"}],name:"setAddress",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_content",type:"bytes32"}],name:"setContent",outputs:[], -type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"}],name:"disown",outputs:[],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"register",outputs:[{name:"",type:"address"}],type:"function"},{anonymous:!1,inputs:[{indexed:!0,name:"name",type:"bytes32"}],name:"Changed",type:"event"},{anonymous:!1,inputs:[{indexed:!0,name:"name",type:"bytes32"},{indexed:!0,name:"addr",type:"address"}],name:"PrimaryChanged",type:"event"}];e.exports=r(i).at(o)},{"./contract":11}],24:[function(t,e,n){var r=t("../utils/utils"),o=t("./property"),i=[],a=[new o({name:"listening",getter:"net_listening"}),new o({name:"peerCount",getter:"net_peerCount",outputFormatter:r.toDecimal})];e.exports={methods:i,properties:a}},{"../utils/utils":7,"./property":25}],25:[function(t,e,n){var r=t("./requestmanager"),o=function(t){this.name=t.name,this.getter=t.getter,this.setter=t.setter,this.outputFormatter=t.outputFormatter,this.inputFormatter=t.inputFormatter};o.prototype.formatInput=function(t){return this.inputFormatter?this.inputFormatter(t):t},o.prototype.formatOutput=function(t){return this.outputFormatter&&null!==t?this.outputFormatter(t):t},o.prototype.attachToObject=function(t){var e={get:this.get.bind(this)},n=this.name.split("."),r=n[0];n.length>1&&(t[n[0]]=t[n[0]]||{},t=t[n[0]],r=n[1]),Object.defineProperty(t,r,e);var o=function(t,e){return t+e.charAt(0).toUpperCase()+e.slice(1)};t[o("get",r)]=this.getAsync.bind(this)},o.prototype.get=function(){return this.formatOutput(r.getInstance().send({method:this.getter}))},o.prototype.getAsync=function(t){var e=this;r.getInstance().sendAsync({method:this.getter},function(n,r){return n?t(n):void t(n,e.formatOutput(r))})},e.exports=o},{"./requestmanager":27}],26:[function(t,e,n){var r=function(){};r.prototype.send=function(t){var e=navigator.qt.callMethod(JSON.stringify(t));return JSON.parse(e)},e.exports=r},{}],27:[function(t,e,n){var r=t("./jsonrpc"),o=t("../utils/utils"),i=t("../utils/config"),a=t("./errors"),s=function(t){return arguments.callee._singletonInstance?arguments.callee._singletonInstance:(arguments.callee._singletonInstance=this,this.provider=t,this.polls=[],this.timeout=null,void this.poll())};s.getInstance=function(){var t=new s;return t},s.prototype.send=function(t){if(!this.provider)return console.error(a.InvalidProvider()),null;var e=r.getInstance().toPayload(t.method,t.params),n=this.provider.send(e);if(!r.getInstance().isValidResponse(n))throw a.InvalidResponse(n);return n.result},s.prototype.sendAsync=function(t,e){if(!this.provider)return e(a.InvalidProvider());var n=r.getInstance().toPayload(t.method,t.params);this.provider.sendAsync(n,function(t,n){return t?e(t):r.getInstance().isValidResponse(n)?void e(null,n.result):e(a.InvalidResponse(n))})},s.prototype.sendBatch=function(t,e){if(!this.provider)return e(a.InvalidProvider());var n=r.getInstance().toBatchPayload(t);this.provider.sendAsync(n,function(t,n){return t?e(t):o.isArray(n)?void e(t,n):e(a.InvalidResponse(n))})},s.prototype.setProvider=function(t){this.provider=t},s.prototype.startPolling=function(t,e,n,r){this.polls.push({data:t,id:e,callback:n,uninstall:r})},s.prototype.stopPolling=function(t){for(var e=this.polls.length;e--;){var n=this.polls[e];n.id===t&&this.polls.splice(e,1)}},s.prototype.reset=function(){this.polls.forEach(function(t){t.uninstall(t.id)}),this.polls=[],this.timeout&&(clearTimeout(this.timeout),this.timeout=null),this.poll()},s.prototype.poll=function(){if(this.timeout=setTimeout(this.poll.bind(this),i.ETH_POLLING_TIMEOUT),this.polls.length){if(!this.provider)return void console.error(a.InvalidProvider());var t=r.getInstance().toBatchPayload(this.polls.map(function(t){return t.data})),e=this;this.provider.sendAsync(t,function(t,n){if(!t){if(!o.isArray(n))throw a.InvalidResponse(n);n.map(function(t,n){return t.callback=e.polls[n].callback,t}).filter(function(t){var e=r.getInstance().isValidResponse(t);return e||t.callback(a.InvalidResponse(t)),e}).filter(function(t){return o.isArray(t.result)&&t.result.length>0}).forEach(function(t){t.callback(null,t.result)})}})}},e.exports=s},{"../utils/config":5,"../utils/utils":7,"./errors":13,"./jsonrpc":21}],28:[function(t,e,n){var r=t("./method"),o=t("./formatters"),i=new r({name:"post",call:"shh_post",params:1,inputFormatter:[o.inputPostFormatter]}),a=new r({name:"newIdentity",call:"shh_newIdentity",params:0}),s=new r({name:"hasIdentity",call:"shh_hasIdentity",params:1}),u=new r({name:"newGroup",call:"shh_newGroup",params:0}),c=new r({name:"addToGroup",call:"shh_addToGroup",params:0}),p=[i,a,s,u,c];e.exports={methods:p}},{"./formatters":17,"./method":22}],29:[function(t,e,n){var r=t("../web3"),o=t("./icap"),i=t("./namereg"),a=t("./contract"),s=function(t,e,n,r){var a=new o(e);if(!a.isValid())throw new Error("invalid iban address");if(a.isDirect())return u(t,a.address(),n,r);if(!r){var s=i.addr(a.institution());return c(t,s,n,a.client())}i.addr(a.insitution(),function(e,o){return c(t,o,n,a.client(),r)})},u=function(t,e,n,o){return r.eth.sendTransaction({address:e,from:t,value:n},o)},c=function(t,e,n,r,o){var i=[{constant:!1,inputs:[{name:"name",type:"bytes32"}],name:"deposit",outputs:[],type:"function"}];return a(i).at(e).deposit(r,{from:t,value:n},o)};e.exports=s},{"../web3":9,"./contract":11,"./icap":20,"./namereg":23}],30:[function(t,e,n){var r=t("./method"),o=function(){var t=function(t){var e=t[0];switch(e){case"latest":return t.pop(),this.params=0,"eth_newBlockFilter";case"pending":return t.pop(),this.params=0,"eth_newPendingTransactionFilter";default:return"eth_newFilter"}},e=new r({name:"newFilter",call:t,params:1}),n=new r({name:"uninstallFilter",call:"eth_uninstallFilter",params:1}),o=new r({name:"getLogs",call:"eth_getFilterLogs",params:1}),i=new r({name:"poll",call:"eth_getFilterChanges",params:1});return[e,n,o,i]},i=function(){var t=new r({name:"newFilter",call:"shh_newFilter",params:1}),e=new r({name:"uninstallFilter",call:"shh_uninstallFilter",params:1}),n=new r({name:"getLogs",call:"shh_getMessages",params:1}),o=new r({name:"poll",call:"shh_getFilterChanges",params:1});return[t,e,n,o]};e.exports={eth:o,shh:i}},{"./method":22}],31:[function(t,e,n){},{}],32:[function(t,e,n){!function(t,r){"object"==typeof n?e.exports=n=r():"function"==typeof define&&define.amd?define([],r):t.CryptoJS=r()}(this,function(){var t=t||function(t,e){var n={},r=n.lib={},o=r.Base=function(){function t(){}return{extend:function(e){t.prototype=this;var n=new t;return e&&n.mixIn(e),n.hasOwnProperty("init")||(n.init=function(){n.$super.init.apply(this,arguments)}),n.init.prototype=n,n.$super=this,n},create:function(){var t=this.extend();return t.init.apply(t,arguments),t},init:function(){},mixIn:function(t){for(var e in t)t.hasOwnProperty(e)&&(this[e]=t[e]);t.hasOwnProperty("toString")&&(this.toString=t.toString)},clone:function(){return this.init.prototype.extend(this)}}}(),i=r.WordArray=o.extend({init:function(t,n){t=this.words=t||[],this.sigBytes=n!=e?n:4*t.length},toString:function(t){return(t||s).stringify(this)},concat:function(t){var e=this.words,n=t.words,r=this.sigBytes,o=t.sigBytes;if(this.clamp(),r%4)for(var i=0;o>i;i++){var a=n[i>>>2]>>>24-i%4*8&255;e[r+i>>>2]|=a<<24-(r+i)%4*8}else for(var i=0;o>i;i+=4)e[r+i>>>2]=n[i>>>2];return this.sigBytes+=o,this},clamp:function(){var e=this.words,n=this.sigBytes;e[n>>>2]&=4294967295<<32-n%4*8,e.length=t.ceil(n/4)},clone:function(){var t=o.clone.call(this);return t.words=this.words.slice(0),t},random:function(e){for(var n,r=[],o=function(e){var e=e,n=987654321,r=4294967295;return function(){n=36969*(65535&n)+(n>>16)&r,e=18e3*(65535&e)+(e>>16)&r;var o=(n<<16)+e&r;return o/=4294967296,o+=.5,o*(t.random()>.5?1:-1)}},a=0;e>a;a+=4){var s=o(4294967296*(n||t.random()));n=987654071*s(),r.push(4294967296*s()|0)}return new i.init(r,e)}}),a=n.enc={},s=a.Hex={stringify:function(t){for(var e=t.words,n=t.sigBytes,r=[],o=0;n>o;o++){var i=e[o>>>2]>>>24-o%4*8&255;r.push((i>>>4).toString(16)),r.push((15&i).toString(16))}return r.join("")},parse:function(t){for(var e=t.length,n=[],r=0;e>r;r+=2)n[r>>>3]|=parseInt(t.substr(r,2),16)<<24-r%8*4;return new i.init(n,e/2)}},u=a.Latin1={stringify:function(t){for(var e=t.words,n=t.sigBytes,r=[],o=0;n>o;o++){var i=e[o>>>2]>>>24-o%4*8&255;r.push(String.fromCharCode(i))}return r.join("")},parse:function(t){for(var e=t.length,n=[],r=0;e>r;r++)n[r>>>2]|=(255&t.charCodeAt(r))<<24-r%4*8;return new i.init(n,e)}},c=a.Utf8={stringify:function(t){try{return decodeURIComponent(escape(u.stringify(t)))}catch(e){throw new Error("Malformed UTF-8 data")}},parse:function(t){return u.parse(unescape(encodeURIComponent(t)))}},p=r.BufferedBlockAlgorithm=o.extend({reset:function(){this._data=new i.init,this._nDataBytes=0},_append:function(t){"string"==typeof t&&(t=c.parse(t)),this._data.concat(t),this._nDataBytes+=t.sigBytes},_process:function(e){var n=this._data,r=n.words,o=n.sigBytes,a=this.blockSize,s=4*a,u=o/s;u=e?t.ceil(u):t.max((0|u)-this._minBufferSize,0);var c=u*a,p=t.min(4*c,o);if(c){for(var l=0;c>l;l+=a)this._doProcessBlock(r,l);var f=r.splice(0,c);n.sigBytes-=p}return new i.init(f,p)},clone:function(){var t=o.clone.call(this);return t._data=this._data.clone(),t},_minBufferSize:0}),l=(r.Hasher=p.extend({cfg:o.extend(),init:function(t){this.cfg=this.cfg.extend(t),this.reset()},reset:function(){p.reset.call(this),this._doReset()},update:function(t){return this._append(t),this._process(),this},finalize:function(t){t&&this._append(t);var e=this._doFinalize();return e},blockSize:16,_createHelper:function(t){return function(e,n){return new t.init(n).finalize(e)}},_createHmacHelper:function(t){return function(e,n){return new l.HMAC.init(t,n).finalize(e)}}}),n.algo={});return n}(Math);return t})},{}],33:[function(t,e,n){!function(r,o,i){"object"==typeof n?e.exports=n=o(t("./core"),t("./x64-core")):"function"==typeof define&&define.amd?define(["./core","./x64-core"],o):o(r.CryptoJS)}(this,function(t){return function(e){var n=t,r=n.lib,o=r.WordArray,i=r.Hasher,a=n.x64,s=a.Word,u=n.algo,c=[],p=[],l=[];!function(){for(var t=1,e=0,n=0;24>n;n++){c[t+5*e]=(n+1)*(n+2)/2%64;var r=e%5,o=(2*t+3*e)%5;t=r,e=o}for(var t=0;5>t;t++)for(var e=0;5>e;e++)p[t+5*e]=e+(2*t+3*e)%5*5;for(var i=1,a=0;24>a;a++){for(var u=0,f=0,m=0;7>m;m++){if(1&i){var h=(1<h?f^=1<t;t++)f[t]=s.create()}();var m=u.SHA3=i.extend({cfg:i.cfg.extend({outputLength:512}),_doReset:function(){for(var t=this._state=[],e=0;25>e;e++)t[e]=new s.init;this.blockSize=(1600-2*this.cfg.outputLength)/32},_doProcessBlock:function(t,e){for(var n=this._state,r=this.blockSize/2,o=0;r>o;o++){var i=t[e+2*o],a=t[e+2*o+1];i=16711935&(i<<8|i>>>24)|4278255360&(i<<24|i>>>8),a=16711935&(a<<8|a>>>24)|4278255360&(a<<24|a>>>8);var s=n[o];s.high^=a,s.low^=i}for(var u=0;24>u;u++){for(var m=0;5>m;m++){for(var h=0,d=0,y=0;5>y;y++){var s=n[m+5*y];h^=s.high,d^=s.low}var g=f[m];g.high=h,g.low=d}for(var m=0;5>m;m++)for(var v=f[(m+4)%5],b=f[(m+1)%5],w=b.high,_=b.low,h=v.high^(w<<1|_>>>31),d=v.low^(_<<1|w>>>31),y=0;5>y;y++){var s=n[m+5*y];s.high^=h,s.low^=d}for(var x=1;25>x;x++){var s=n[x],F=s.high,B=s.low,I=c[x];if(32>I)var h=F<>>32-I,d=B<>>32-I;else var h=B<>>64-I,d=F<>>64-I;var N=f[p[x]];N.high=h,N.low=d}var k=f[0],A=n[0];k.high=A.high,k.low=A.low;for(var m=0;5>m;m++)for(var y=0;5>y;y++){var x=m+5*y,s=n[x],P=f[x],O=f[(m+1)%5+5*y],T=f[(m+2)%5+5*y];s.high=P.high^~O.high&T.high,s.low=P.low^~O.low&T.low}var s=n[0],D=l[u];s.high^=D.high,s.low^=D.low}},_doFinalize:function(){var t=this._data,n=t.words,r=(8*this._nDataBytes,8*t.sigBytes),i=32*this.blockSize;n[r>>>5]|=1<<24-r%32,n[(e.ceil((r+1)/i)*i>>>5)-1]|=128,t.sigBytes=4*n.length,this._process();for(var a=this._state,s=this.cfg.outputLength/8,u=s/8,c=[],p=0;u>p;p++){var l=a[p],f=l.high,m=l.low;f=16711935&(f<<8|f>>>24)|4278255360&(f<<24|f>>>8),m=16711935&(m<<8|m>>>24)|4278255360&(m<<24|m>>>8),c.push(m),c.push(f)}return new o.init(c,s)},clone:function(){for(var t=i.clone.call(this),e=t._state=this._state.slice(0),n=0;25>n;n++)e[n]=e[n].clone();return t}});n.SHA3=i._createHelper(m),n.HmacSHA3=i._createHmacHelper(m)}(Math),t.SHA3})},{"./core":32,"./x64-core":34}],34:[function(t,e,n){!function(r,o){"object"==typeof n?e.exports=n=o(t("./core")):"function"==typeof define&&define.amd?define(["./core"],o):o(r.CryptoJS)}(this,function(t){return function(e){{var n=t,r=n.lib,o=r.Base,i=r.WordArray,a=n.x64={};a.Word=o.extend({init:function(t,e){this.high=t,this.low=e}}),a.WordArray=o.extend({init:function(t,n){t=this.words=t||[],this.sigBytes=n!=e?n:8*t.length},toX32:function(){for(var t=this.words,e=t.length,n=[],r=0;e>r;r++){var o=t[r];n.push(o.high),n.push(o.low)}return i.create(n,this.sigBytes)},clone:function(){for(var t=o.clone.call(this),e=t.words=this.words.slice(0),n=e.length,r=0;n>r;r++)e[r]=e[r].clone();return t}})}}(),t})},{"./core":32}],"bignumber.js":[function(t,e,n){"use strict";e.exports=BigNumber},{}],web3:[function(t,e,n){var r=t("./lib/web3");r.providers.HttpProvider=t("./lib/web3/httpprovider"),r.providers.QtSyncProvider=t("./lib/web3/qtsync"),r.eth.contract=t("./lib/web3/contract"),r.eth.namereg=t("./lib/web3/namereg"),r.eth.sendIBANTransaction=t("./lib/web3/transfer"),"undefined"!=typeof window&&"undefined"==typeof window.web3&&(window.web3=r),e.exports=r},{"./lib/web3":9,"./lib/web3/contract":11,"./lib/web3/httpprovider":19,"./lib/web3/namereg":23,"./lib/web3/qtsync":26,"./lib/web3/transfer":29}]},{},["web3"]); \ No newline at end of file diff --git a/libjsqrc/ethereumjs/dist/web3.js b/libjsqrc/ethereumjs/dist/web3.js index 2ff72ea6c..ec5cdfe83 100644 --- a/libjsqrc/ethereumjs/dist/web3.js +++ b/libjsqrc/ethereumjs/dist/web3.js @@ -1388,6 +1388,7 @@ var Filter = require('./web3/filter'); var utils = require('./utils/utils'); var formatters = require('./web3/formatters'); var RequestManager = require('./web3/requestmanager'); +var Method = require('./web3/method'); var c = require('./utils/config'); var Property = require('./web3/property'); var Batch = require('./web3/batch'); @@ -1512,10 +1513,22 @@ setupProperties(web3.eth, eth.properties); setupMethods(web3.db, db.methods); setupMethods(web3.shh, shh.methods); +web3.admin = {}; +web3.admin.setSessionKey = function(s) { web3.admin.sessionKey = s; }; + +var blockQueueStatus = new Method({ + name: 'blockQueueStatus', + call: 'admin_eth_blockQueueStatus', + params: 1, + inputFormatter: [function() { return web3.admin.sessionKey; }] +}); + +setupMethods(web3.admin, [blockQueueStatus]); + module.exports = web3; -},{"./utils/config":5,"./utils/sha3":6,"./utils/utils":7,"./version.json":8,"./web3/batch":10,"./web3/db":12,"./web3/eth":14,"./web3/filter":16,"./web3/formatters":17,"./web3/net":24,"./web3/property":25,"./web3/requestmanager":27,"./web3/shh":28,"./web3/watches":30}],10:[function(require,module,exports){ +},{"./utils/config":5,"./utils/sha3":6,"./utils/utils":7,"./version.json":8,"./web3/batch":10,"./web3/db":12,"./web3/eth":14,"./web3/filter":16,"./web3/formatters":17,"./web3/method":22,"./web3/net":24,"./web3/property":25,"./web3/requestmanager":27,"./web3/shh":28,"./web3/watches":30}],10:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1938,11 +1951,11 @@ var uncleCountCall = function (args) { /// @returns an array of objects describing web3.eth api methods var getBalance = new Method({ - name: 'getBalance', - call: 'eth_getBalance', - params: 2, - inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter], - outputFormatter: formatters.outputBigNumberFormatter + name: 'getBalance', + call: 'eth_getBalance', + params: 2, + inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter], + outputFormatter: formatters.outputBigNumberFormatter }); var getStorageAt = new Method({ @@ -8262,4 +8275,4 @@ module.exports = web3; },{"./lib/web3":9,"./lib/web3/contract":11,"./lib/web3/httpprovider":19,"./lib/web3/namereg":23,"./lib/web3/qtsync":26,"./lib/web3/transfer":29}]},{},["web3"]) -//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJsaWIvc29saWRpdHkvY29kZXIuanMiLCJsaWIvc29saWRpdHkvZm9ybWF0dGVycy5qcyIsImxpYi9zb2xpZGl0eS9wYXJhbS5qcyIsImxpYi91dGlscy9icm93c2VyLXhoci5qcyIsImxpYi91dGlscy9jb25maWcuanMiLCJsaWIvdXRpbHMvc2hhMy5qcyIsImxpYi91dGlscy91dGlscy5qcyIsImxpYi92ZXJzaW9uLmpzb24iLCJsaWIvd2ViMy5qcyIsImxpYi93ZWIzL2JhdGNoLmpzIiwibGliL3dlYjMvY29udHJhY3QuanMiLCJsaWIvd2ViMy9kYi5qcyIsImxpYi93ZWIzL2Vycm9ycy5qcyIsImxpYi93ZWIzL2V0aC5qcyIsImxpYi93ZWIzL2V2ZW50LmpzIiwibGliL3dlYjMvZmlsdGVyLmpzIiwibGliL3dlYjMvZm9ybWF0dGVycy5qcyIsImxpYi93ZWIzL2Z1bmN0aW9uLmpzIiwibGliL3dlYjMvaHR0cHByb3ZpZGVyLmpzIiwibGliL3dlYjMvaWNhcC5qcyIsImxpYi93ZWIzL2pzb25ycGMuanMiLCJsaWIvd2ViMy9tZXRob2QuanMiLCJsaWIvd2ViMy9uYW1lcmVnLmpzIiwibGliL3dlYjMvbmV0LmpzIiwibGliL3dlYjMvcHJvcGVydHkuanMiLCJsaWIvd2ViMy9xdHN5bmMuanMiLCJsaWIvd2ViMy9yZXF1ZXN0bWFuYWdlci5qcyIsImxpYi93ZWIzL3NoaC5qcyIsImxpYi93ZWIzL3RyYW5zZmVyLmpzIiwibGliL3dlYjMvd2F0Y2hlcy5qcyIsIm5vZGVfbW9kdWxlcy9icm93c2VyaWZ5L2xpYi9fZW1wdHkuanMiLCJub2RlX21vZHVsZXMvY3J5cHRvLWpzL2NvcmUuanMiLCJub2RlX21vZHVsZXMvY3J5cHRvLWpzL3NoYTMuanMiLCJub2RlX21vZHVsZXMvY3J5cHRvLWpzL3g2NC1jb3JlLmpzIiwiYmlnbnVtYmVyLmpzIiwiaW5kZXguanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsZkE7QUFDQTtBQUNBO0FBQ0E7O0FDSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25SQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuTUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMU5BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0UEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsSEE7O0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcnVCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xVQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvU0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzbkZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBcbiAqIEBmaWxlIGNvZGVyLmpzXG4gKiBAYXV0aG9yIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbnZhciBCaWdOdW1iZXIgPSByZXF1aXJlKCdiaWdudW1iZXIuanMnKTtcbnZhciB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzL3V0aWxzJyk7XG52YXIgZiA9IHJlcXVpcmUoJy4vZm9ybWF0dGVycycpO1xudmFyIFNvbGlkaXR5UGFyYW0gPSByZXF1aXJlKCcuL3BhcmFtJyk7XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gY2hlY2sgaWYgYSB0eXBlIGlzIGFuIGFycmF5IHR5cGVcbiAqXG4gKiBAbWV0aG9kIGlzQXJyYXlUeXBlXG4gKiBAcGFyYW0ge1N0cmluZ30gdHlwZVxuICogQHJldHVybiB7Qm9vbH0gdHJ1ZSBpcyB0aGUgdHlwZSBpcyBhbiBhcnJheSwgb3RoZXJ3aXNlIGZhbHNlXG4gKi9cbnZhciBpc0FycmF5VHlwZSA9IGZ1bmN0aW9uICh0eXBlKSB7XG4gICAgcmV0dXJuIHR5cGUuc2xpY2UoLTIpID09PSAnW10nO1xufTtcblxuLyoqXG4gKiBTb2xpZGl0eVR5cGUgcHJvdG90eXBlIGlzIHVzZWQgdG8gZW5jb2RlL2RlY29kZSBzb2xpZGl0eSBwYXJhbXMgb2YgY2VydGFpbiB0eXBlXG4gKi9cbnZhciBTb2xpZGl0eVR5cGUgPSBmdW5jdGlvbiAoY29uZmlnKSB7XG4gICAgdGhpcy5fbmFtZSA9IGNvbmZpZy5uYW1lO1xuICAgIHRoaXMuX21hdGNoID0gY29uZmlnLm1hdGNoO1xuICAgIHRoaXMuX21vZGUgPSBjb25maWcubW9kZTtcbiAgICB0aGlzLl9pbnB1dEZvcm1hdHRlciA9IGNvbmZpZy5pbnB1dEZvcm1hdHRlcjtcbiAgICB0aGlzLl9vdXRwdXRGb3JtYXR0ZXIgPSBjb25maWcub3V0cHV0Rm9ybWF0dGVyO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBkZXRlcm1pbmUgaWYgdGhpcyBTb2xpZGl0eVR5cGUgZG8gbWF0Y2ggZ2l2ZW4gdHlwZVxuICpcbiAqIEBtZXRob2QgaXNUeXBlXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZVxuICogQHJldHVybiB7Qm9vbH0gdHJ1ZSBpZiB0eXBlIG1hdGNoIHRoaXMgU29saWRpdHlUeXBlLCBvdGhlcndpc2UgZmFsc2VcbiAqL1xuU29saWRpdHlUeXBlLnByb3RvdHlwZS5pc1R5cGUgPSBmdW5jdGlvbiAobmFtZSkge1xuICAgIGlmICh0aGlzLl9tYXRjaCA9PT0gJ3N0cmljdCcpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX25hbWUgPT09IG5hbWUgfHwgKG5hbWUuaW5kZXhPZih0aGlzLl9uYW1lKSA9PT0gMCAmJiBuYW1lLnNsaWNlKHRoaXMuX25hbWUubGVuZ3RoKSA9PT0gJ1tdJyk7XG4gICAgfSBlbHNlIGlmICh0aGlzLl9tYXRjaCA9PT0gJ3ByZWZpeCcpIHtcbiAgICAgICAgLy8gVE9ETyBiZXR0ZXIgdHlwZSBkZXRlY3Rpb24hXG4gICAgICAgIHJldHVybiBuYW1lLmluZGV4T2YodGhpcy5fbmFtZSkgPT09IDA7XG4gICAgfVxufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byB0cmFuc2Zvcm0gcGxhaW4gcGFyYW0gdG8gU29saWRpdHlQYXJhbSBvYmplY3RcbiAqXG4gKiBAbWV0aG9kIGZvcm1hdElucHV0XG4gKiBAcGFyYW0ge09iamVjdH0gcGFyYW0gLSBwbGFpbiBvYmplY3QsIG9yIGFuIGFycmF5IG9mIG9iamVjdHNcbiAqIEBwYXJhbSB7Qm9vbH0gYXJyYXlUeXBlIC0gdHJ1ZSBpZiBhIHBhcmFtIHNob3VsZCBiZSBlbmNvZGVkIGFzIGFuIGFycmF5XG4gKiBAcmV0dXJuIHtTb2xpZGl0eVBhcmFtfSBlbmNvZGVkIHBhcmFtIHdyYXBwZWQgaW4gU29saWRpdHlQYXJhbSBvYmplY3QgXG4gKi9cblNvbGlkaXR5VHlwZS5wcm90b3R5cGUuZm9ybWF0SW5wdXQgPSBmdW5jdGlvbiAocGFyYW0sIGFycmF5VHlwZSkge1xuICAgIGlmICh1dGlscy5pc0FycmF5KHBhcmFtKSAmJiBhcnJheVR5cGUpIHsgLy8gVE9ETzogc2hvdWxkIGZhaWwgaWYgdGhpcyB0d28gYXJlIG5vdCB0aGUgc2FtZVxuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgIHJldHVybiBwYXJhbS5tYXAoZnVuY3Rpb24gKHApIHtcbiAgICAgICAgICAgIHJldHVybiBzZWxmLl9pbnB1dEZvcm1hdHRlcihwKTtcbiAgICAgICAgfSkucmVkdWNlKGZ1bmN0aW9uIChhY2MsIGN1cnJlbnQpIHtcbiAgICAgICAgICAgIHJldHVybiBhY2MuY29tYmluZShjdXJyZW50KTtcbiAgICAgICAgfSwgZi5mb3JtYXRJbnB1dEludChwYXJhbS5sZW5ndGgpKS53aXRoT2Zmc2V0KDMyKTtcbiAgICB9IFxuICAgIHJldHVybiB0aGlzLl9pbnB1dEZvcm1hdHRlcihwYXJhbSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIHRyYW5zb2Zvcm0gU29saWRpdHlQYXJhbSB0byBwbGFpbiBwYXJhbVxuICpcbiAqIEBtZXRob2QgZm9ybWF0T3V0cHV0XG4gKiBAcGFyYW0ge1NvbGlkaXR5UGFyYW19IGJ5dGVBcnJheVxuICogQHBhcmFtIHtCb29sfSBhcnJheVR5cGUgLSB0cnVlIGlmIGEgcGFyYW0gc2hvdWxkIGJlIGRlY29kZWQgYXMgYW4gYXJyYXlcbiAqIEByZXR1cm4ge09iamVjdH0gcGxhaW4gZGVjb2RlZCBwYXJhbVxuICovXG5Tb2xpZGl0eVR5cGUucHJvdG90eXBlLmZvcm1hdE91dHB1dCA9IGZ1bmN0aW9uIChwYXJhbSwgYXJyYXlUeXBlKSB7XG4gICAgaWYgKGFycmF5VHlwZSkge1xuICAgICAgICAvLyBsZXQncyBhc3N1bWUsIHRoYXQgd2Ugc29saWRpdHkgd2lsbCBuZXZlciByZXR1cm4gbG9uZyBhcnJheXMgOlAgXG4gICAgICAgIHZhciByZXN1bHQgPSBbXTtcbiAgICAgICAgdmFyIGxlbmd0aCA9IG5ldyBCaWdOdW1iZXIocGFyYW0uZHluYW1pY1BhcnQoKS5zbGljZSgwLCA2NCksIDE2KTtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGggKiA2NDsgaSArPSA2NCkge1xuICAgICAgICAgICAgcmVzdWx0LnB1c2godGhpcy5fb3V0cHV0Rm9ybWF0dGVyKG5ldyBTb2xpZGl0eVBhcmFtKHBhcmFtLmR5bmFtaWNQYXJ0KCkuc3Vic3RyKGkgKyA2NCwgNjQpKSkpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLl9vdXRwdXRGb3JtYXR0ZXIocGFyYW0pO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBzbGljZSBzaW5nbGUgcGFyYW0gZnJvbSBieXRlc1xuICpcbiAqIEBtZXRob2Qgc2xpY2VQYXJhbVxuICogQHBhcmFtIHtTdHJpbmd9IGJ5dGVzXG4gKiBAcGFyYW0ge051bWJlcn0gaW5kZXggb2YgcGFyYW0gdG8gc2xpY2VcbiAqIEBwYXJhbSB7U3RyaW5nfSB0eXBlXG4gKiBAcmV0dXJucyB7U29saWRpdHlQYXJhbX0gcGFyYW1cbiAqL1xuU29saWRpdHlUeXBlLnByb3RvdHlwZS5zbGljZVBhcmFtID0gZnVuY3Rpb24gKGJ5dGVzLCBpbmRleCwgdHlwZSkge1xuICAgIGlmICh0aGlzLl9tb2RlID09PSAnYnl0ZXMnKSB7XG4gICAgICAgIHJldHVybiBTb2xpZGl0eVBhcmFtLmRlY29kZUJ5dGVzKGJ5dGVzLCBpbmRleCk7XG4gICAgfSBlbHNlIGlmIChpc0FycmF5VHlwZSh0eXBlKSkge1xuICAgICAgICByZXR1cm4gU29saWRpdHlQYXJhbS5kZWNvZGVBcnJheShieXRlcywgaW5kZXgpO1xuICAgIH1cbiAgICByZXR1cm4gU29saWRpdHlQYXJhbS5kZWNvZGVQYXJhbShieXRlcywgaW5kZXgpO1xufTtcblxuLyoqXG4gKiBTb2xpZGl0eUNvZGVyIHByb3RvdHlwZSBzaG91bGQgYmUgdXNlZCB0byBlbmNvZGUvZGVjb2RlIHNvbGlkaXR5IHBhcmFtcyBvZiBhbnkgdHlwZVxuICovXG52YXIgU29saWRpdHlDb2RlciA9IGZ1bmN0aW9uICh0eXBlcykge1xuICAgIHRoaXMuX3R5cGVzID0gdHlwZXM7XG59O1xuXG4vKipcbiAqIFRoaXMgbWV0aG9kIHNob3VsZCBiZSB1c2VkIHRvIHRyYW5zZm9ybSB0eXBlIHRvIFNvbGlkaXR5VHlwZVxuICpcbiAqIEBtZXRob2QgX3JlcXVpcmVUeXBlXG4gKiBAcGFyYW0ge1N0cmluZ30gdHlwZVxuICogQHJldHVybnMge1NvbGlkaXR5VHlwZX0gXG4gKiBAdGhyb3dzIHtFcnJvcn0gdGhyb3dzIGlmIG5vIG1hdGNoaW5nIHR5cGUgaXMgZm91bmRcbiAqL1xuU29saWRpdHlDb2Rlci5wcm90b3R5cGUuX3JlcXVpcmVUeXBlID0gZnVuY3Rpb24gKHR5cGUpIHtcbiAgICB2YXIgc29saWRpdHlUeXBlID0gdGhpcy5fdHlwZXMuZmlsdGVyKGZ1bmN0aW9uICh0KSB7XG4gICAgICAgIHJldHVybiB0LmlzVHlwZSh0eXBlKTtcbiAgICB9KVswXTtcblxuICAgIGlmICghc29saWRpdHlUeXBlKSB7XG4gICAgICAgIHRocm93IEVycm9yKCdpbnZhbGlkIHNvbGlkaXR5IHR5cGUhOiAnICsgdHlwZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNvbGlkaXR5VHlwZTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gdHJhbnNmb3JtIHBsYWluIHBhcmFtIG9mIGdpdmVuIHR5cGUgdG8gU29saWRpdHlQYXJhbVxuICpcbiAqIEBtZXRob2QgX2Zvcm1hdElucHV0XG4gKiBAcGFyYW0ge1N0cmluZ30gdHlwZSBvZiBwYXJhbVxuICogQHBhcmFtIHtPYmplY3R9IHBsYWluIHBhcmFtXG4gKiBAcmV0dXJuIHtTb2xpZGl0eVBhcmFtfVxuICovXG5Tb2xpZGl0eUNvZGVyLnByb3RvdHlwZS5fZm9ybWF0SW5wdXQgPSBmdW5jdGlvbiAodHlwZSwgcGFyYW0pIHtcbiAgICByZXR1cm4gdGhpcy5fcmVxdWlyZVR5cGUodHlwZSkuZm9ybWF0SW5wdXQocGFyYW0sIGlzQXJyYXlUeXBlKHR5cGUpKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZW5jb2RlIHBsYWluIHBhcmFtXG4gKlxuICogQG1ldGhvZCBlbmNvZGVQYXJhbVxuICogQHBhcmFtIHtTdHJpbmd9IHR5cGVcbiAqIEBwYXJhbSB7T2JqZWN0fSBwbGFpbiBwYXJhbVxuICogQHJldHVybiB7U3RyaW5nfSBlbmNvZGVkIHBsYWluIHBhcmFtXG4gKi9cblNvbGlkaXR5Q29kZXIucHJvdG90eXBlLmVuY29kZVBhcmFtID0gZnVuY3Rpb24gKHR5cGUsIHBhcmFtKSB7XG4gICAgcmV0dXJuIHRoaXMuX2Zvcm1hdElucHV0KHR5cGUsIHBhcmFtKS5lbmNvZGUoKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZW5jb2RlIGxpc3Qgb2YgcGFyYW1zXG4gKlxuICogQG1ldGhvZCBlbmNvZGVQYXJhbXNcbiAqIEBwYXJhbSB7QXJyYXl9IHR5cGVzXG4gKiBAcGFyYW0ge0FycmF5fSBwYXJhbXNcbiAqIEByZXR1cm4ge1N0cmluZ30gZW5jb2RlZCBsaXN0IG9mIHBhcmFtc1xuICovXG5Tb2xpZGl0eUNvZGVyLnByb3RvdHlwZS5lbmNvZGVQYXJhbXMgPSBmdW5jdGlvbiAodHlwZXMsIHBhcmFtcykge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgc29saWRpdHlQYXJhbXMgPSB0eXBlcy5tYXAoZnVuY3Rpb24gKHR5cGUsIGluZGV4KSB7XG4gICAgICAgIHJldHVybiBzZWxmLl9mb3JtYXRJbnB1dCh0eXBlLCBwYXJhbXNbaW5kZXhdKTtcbiAgICB9KTtcblxuICAgIHJldHVybiBTb2xpZGl0eVBhcmFtLmVuY29kZUxpc3Qoc29saWRpdHlQYXJhbXMpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBkZWNvZGUgYnl0ZXMgdG8gcGxhaW4gcGFyYW1cbiAqXG4gKiBAbWV0aG9kIGRlY29kZVBhcmFtXG4gKiBAcGFyYW0ge1N0cmluZ30gdHlwZVxuICogQHBhcmFtIHtTdHJpbmd9IGJ5dGVzXG4gKiBAcmV0dXJuIHtPYmplY3R9IHBsYWluIHBhcmFtXG4gKi9cblNvbGlkaXR5Q29kZXIucHJvdG90eXBlLmRlY29kZVBhcmFtID0gZnVuY3Rpb24gKHR5cGUsIGJ5dGVzKSB7XG4gICAgcmV0dXJuIHRoaXMuZGVjb2RlUGFyYW1zKFt0eXBlXSwgYnl0ZXMpWzBdO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBkZWNvZGUgbGlzdCBvZiBwYXJhbXNcbiAqXG4gKiBAbWV0aG9kIGRlY29kZVBhcmFtXG4gKiBAcGFyYW0ge0FycmF5fSB0eXBlc1xuICogQHBhcmFtIHtTdHJpbmd9IGJ5dGVzXG4gKiBAcmV0dXJuIHtBcnJheX0gYXJyYXkgb2YgcGxhaW4gcGFyYW1zXG4gKi9cblNvbGlkaXR5Q29kZXIucHJvdG90eXBlLmRlY29kZVBhcmFtcyA9IGZ1bmN0aW9uICh0eXBlcywgYnl0ZXMpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgcmV0dXJuIHR5cGVzLm1hcChmdW5jdGlvbiAodHlwZSwgaW5kZXgpIHtcbiAgICAgICAgdmFyIHNvbGlkaXR5VHlwZSA9IHNlbGYuX3JlcXVpcmVUeXBlKHR5cGUpO1xuICAgICAgICB2YXIgcCA9IHNvbGlkaXR5VHlwZS5zbGljZVBhcmFtKGJ5dGVzLCBpbmRleCwgdHlwZSk7XG4gICAgICAgIHJldHVybiBzb2xpZGl0eVR5cGUuZm9ybWF0T3V0cHV0KHAsIGlzQXJyYXlUeXBlKHR5cGUpKTtcbiAgICB9KTtcbn07XG5cbnZhciBjb2RlciA9IG5ldyBTb2xpZGl0eUNvZGVyKFtcbiAgICBuZXcgU29saWRpdHlUeXBlKHtcbiAgICAgICAgbmFtZTogJ2FkZHJlc3MnLFxuICAgICAgICBtYXRjaDogJ3N0cmljdCcsXG4gICAgICAgIG1vZGU6ICd2YWx1ZScsXG4gICAgICAgIGlucHV0Rm9ybWF0dGVyOiBmLmZvcm1hdElucHV0SW50LFxuICAgICAgICBvdXRwdXRGb3JtYXR0ZXI6IGYuZm9ybWF0T3V0cHV0QWRkcmVzc1xuICAgIH0pLFxuICAgIG5ldyBTb2xpZGl0eVR5cGUoe1xuICAgICAgICBuYW1lOiAnYm9vbCcsXG4gICAgICAgIG1hdGNoOiAnc3RyaWN0JyxcbiAgICAgICAgbW9kZTogJ3ZhbHVlJyxcbiAgICAgICAgaW5wdXRGb3JtYXR0ZXI6IGYuZm9ybWF0SW5wdXRCb29sLFxuICAgICAgICBvdXRwdXRGb3JtYXR0ZXI6IGYuZm9ybWF0T3V0cHV0Qm9vbFxuICAgIH0pLFxuICAgIG5ldyBTb2xpZGl0eVR5cGUoe1xuICAgICAgICBuYW1lOiAnaW50JyxcbiAgICAgICAgbWF0Y2g6ICdwcmVmaXgnLFxuICAgICAgICBtb2RlOiAndmFsdWUnLFxuICAgICAgICBpbnB1dEZvcm1hdHRlcjogZi5mb3JtYXRJbnB1dEludCxcbiAgICAgICAgb3V0cHV0Rm9ybWF0dGVyOiBmLmZvcm1hdE91dHB1dEludCxcbiAgICB9KSxcbiAgICBuZXcgU29saWRpdHlUeXBlKHtcbiAgICAgICAgbmFtZTogJ3VpbnQnLFxuICAgICAgICBtYXRjaDogJ3ByZWZpeCcsXG4gICAgICAgIG1vZGU6ICd2YWx1ZScsXG4gICAgICAgIGlucHV0Rm9ybWF0dGVyOiBmLmZvcm1hdElucHV0SW50LFxuICAgICAgICBvdXRwdXRGb3JtYXR0ZXI6IGYuZm9ybWF0T3V0cHV0VUludFxuICAgIH0pLFxuICAgIG5ldyBTb2xpZGl0eVR5cGUoe1xuICAgICAgICBuYW1lOiAnYnl0ZXMnLFxuICAgICAgICBtYXRjaDogJ3N0cmljdCcsXG4gICAgICAgIG1vZGU6ICdieXRlcycsXG4gICAgICAgIGlucHV0Rm9ybWF0dGVyOiBmLmZvcm1hdElucHV0RHluYW1pY0J5dGVzLFxuICAgICAgICBvdXRwdXRGb3JtYXR0ZXI6IGYuZm9ybWF0T3V0cHV0RHluYW1pY0J5dGVzXG4gICAgfSksXG4gICAgbmV3IFNvbGlkaXR5VHlwZSh7XG4gICAgICAgIG5hbWU6ICdieXRlcycsXG4gICAgICAgIG1hdGNoOiAncHJlZml4JyxcbiAgICAgICAgbW9kZTogJ3ZhbHVlJyxcbiAgICAgICAgaW5wdXRGb3JtYXR0ZXI6IGYuZm9ybWF0SW5wdXRCeXRlcyxcbiAgICAgICAgb3V0cHV0Rm9ybWF0dGVyOiBmLmZvcm1hdE91dHB1dEJ5dGVzXG4gICAgfSksXG4gICAgbmV3IFNvbGlkaXR5VHlwZSh7XG4gICAgICAgIG5hbWU6ICdyZWFsJyxcbiAgICAgICAgbWF0Y2g6ICdwcmVmaXgnLFxuICAgICAgICBtb2RlOiAndmFsdWUnLFxuICAgICAgICBpbnB1dEZvcm1hdHRlcjogZi5mb3JtYXRJbnB1dFJlYWwsXG4gICAgICAgIG91dHB1dEZvcm1hdHRlcjogZi5mb3JtYXRPdXRwdXRSZWFsXG4gICAgfSksXG4gICAgbmV3IFNvbGlkaXR5VHlwZSh7XG4gICAgICAgIG5hbWU6ICd1cmVhbCcsXG4gICAgICAgIG1hdGNoOiAncHJlZml4JyxcbiAgICAgICAgbW9kZTogJ3ZhbHVlJyxcbiAgICAgICAgaW5wdXRGb3JtYXR0ZXI6IGYuZm9ybWF0SW5wdXRSZWFsLFxuICAgICAgICBvdXRwdXRGb3JtYXR0ZXI6IGYuZm9ybWF0T3V0cHV0VVJlYWxcbiAgICB9KVxuXSk7XG5cbm1vZHVsZS5leHBvcnRzID0gY29kZXI7XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqIFxuICogQGZpbGUgZm9ybWF0dGVycy5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgQmlnTnVtYmVyID0gcmVxdWlyZSgnYmlnbnVtYmVyLmpzJyk7XG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy91dGlscycpO1xudmFyIGMgPSByZXF1aXJlKCcuLi91dGlscy9jb25maWcnKTtcbnZhciBTb2xpZGl0eVBhcmFtID0gcmVxdWlyZSgnLi9wYXJhbScpO1xuXG5cbi8qKlxuICogRm9ybWF0cyBpbnB1dCB2YWx1ZSB0byBieXRlIHJlcHJlc2VudGF0aW9uIG9mIGludFxuICogSWYgdmFsdWUgaXMgbmVnYXRpdmUsIHJldHVybiBpdCdzIHR3bydzIGNvbXBsZW1lbnRcbiAqIElmIHRoZSB2YWx1ZSBpcyBmbG9hdGluZyBwb2ludCwgcm91bmQgaXQgZG93blxuICpcbiAqIEBtZXRob2QgZm9ybWF0SW5wdXRJbnRcbiAqIEBwYXJhbSB7U3RyaW5nfE51bWJlcnxCaWdOdW1iZXJ9IHZhbHVlIHRoYXQgbmVlZHMgdG8gYmUgZm9ybWF0dGVkXG4gKiBAcmV0dXJucyB7U29saWRpdHlQYXJhbX1cbiAqL1xudmFyIGZvcm1hdElucHV0SW50ID0gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgdmFyIHBhZGRpbmcgPSBjLkVUSF9QQURESU5HICogMjtcbiAgICBCaWdOdW1iZXIuY29uZmlnKGMuRVRIX0JJR05VTUJFUl9ST1VORElOR19NT0RFKTtcbiAgICB2YXIgcmVzdWx0ID0gdXRpbHMucGFkTGVmdCh1dGlscy50b1R3b3NDb21wbGVtZW50KHZhbHVlKS5yb3VuZCgpLnRvU3RyaW5nKDE2KSwgcGFkZGluZyk7XG4gICAgcmV0dXJuIG5ldyBTb2xpZGl0eVBhcmFtKHJlc3VsdCk7XG59O1xuXG4vKipcbiAqIEZvcm1hdHMgaW5wdXQgdmFsdWUgdG8gYnl0ZSByZXByZXNlbnRhdGlvbiBvZiBzdHJpbmdcbiAqXG4gKiBAbWV0aG9kIGZvcm1hdElucHV0Qnl0ZXNcbiAqIEBwYXJhbSB7U3RyaW5nfVxuICogQHJldHVybnMge1NvbGlkaXR5UGFyYW19XG4gKi9cbnZhciBmb3JtYXRJbnB1dEJ5dGVzID0gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgdmFyIHJlc3VsdCA9IHV0aWxzLmZyb21Bc2NpaSh2YWx1ZSwgYy5FVEhfUEFERElORykuc3Vic3RyKDIpO1xuICAgIHJldHVybiBuZXcgU29saWRpdHlQYXJhbShyZXN1bHQpO1xufTtcblxuLyoqXG4gKiBGb3JtYXRzIGlucHV0IHZhbHVlIHRvIGJ5dGUgcmVwcmVzZW50YXRpb24gb2Ygc3RyaW5nXG4gKlxuICogQG1ldGhvZCBmb3JtYXRJbnB1dER5bmFtaWNCeXRlc1xuICogQHBhcmFtIHtTdHJpbmd9XG4gKiBAcmV0dXJucyB7U29saWRpdHlQYXJhbX1cbiAqL1xudmFyIGZvcm1hdElucHV0RHluYW1pY0J5dGVzID0gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgdmFyIHJlc3VsdCA9IHV0aWxzLmZyb21Bc2NpaSh2YWx1ZSwgYy5FVEhfUEFERElORykuc3Vic3RyKDIpO1xuICAgIHJldHVybiBuZXcgU29saWRpdHlQYXJhbShmb3JtYXRJbnB1dEludCh2YWx1ZS5sZW5ndGgpLnZhbHVlICsgcmVzdWx0LCAzMik7XG59O1xuXG4vKipcbiAqIEZvcm1hdHMgaW5wdXQgdmFsdWUgdG8gYnl0ZSByZXByZXNlbnRhdGlvbiBvZiBib29sXG4gKlxuICogQG1ldGhvZCBmb3JtYXRJbnB1dEJvb2xcbiAqIEBwYXJhbSB7Qm9vbGVhbn1cbiAqIEByZXR1cm5zIHtTb2xpZGl0eVBhcmFtfVxuICovXG52YXIgZm9ybWF0SW5wdXRCb29sID0gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgdmFyIHJlc3VsdCA9ICcwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAnICsgKHZhbHVlID8gICcxJyA6ICcwJyk7XG4gICAgcmV0dXJuIG5ldyBTb2xpZGl0eVBhcmFtKHJlc3VsdCk7XG59O1xuXG4vKipcbiAqIEZvcm1hdHMgaW5wdXQgdmFsdWUgdG8gYnl0ZSByZXByZXNlbnRhdGlvbiBvZiByZWFsXG4gKiBWYWx1ZXMgYXJlIG11bHRpcGxpZWQgYnkgMl5tIGFuZCBlbmNvZGVkIGFzIGludGVnZXJzXG4gKlxuICogQG1ldGhvZCBmb3JtYXRJbnB1dFJlYWxcbiAqIEBwYXJhbSB7U3RyaW5nfE51bWJlcnxCaWdOdW1iZXJ9XG4gKiBAcmV0dXJucyB7U29saWRpdHlQYXJhbX1cbiAqL1xudmFyIGZvcm1hdElucHV0UmVhbCA9IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgIHJldHVybiBmb3JtYXRJbnB1dEludChuZXcgQmlnTnVtYmVyKHZhbHVlKS50aW1lcyhuZXcgQmlnTnVtYmVyKDIpLnBvdygxMjgpKSk7XG59O1xuXG4vKipcbiAqIENoZWNrIGlmIGlucHV0IHZhbHVlIGlzIG5lZ2F0aXZlXG4gKlxuICogQG1ldGhvZCBzaWduZWRJc05lZ2F0aXZlXG4gKiBAcGFyYW0ge1N0cmluZ30gdmFsdWUgaXMgaGV4IGZvcm1hdFxuICogQHJldHVybnMge0Jvb2xlYW59IHRydWUgaWYgaXQgaXMgbmVnYXRpdmUsIG90aGVyd2lzZSBmYWxzZVxuICovXG52YXIgc2lnbmVkSXNOZWdhdGl2ZSA9IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgIHJldHVybiAobmV3IEJpZ051bWJlcih2YWx1ZS5zdWJzdHIoMCwgMSksIDE2KS50b1N0cmluZygyKS5zdWJzdHIoMCwgMSkpID09PSAnMSc7XG59O1xuXG4vKipcbiAqIEZvcm1hdHMgcmlnaHQtYWxpZ25lZCBvdXRwdXQgYnl0ZXMgdG8gaW50XG4gKlxuICogQG1ldGhvZCBmb3JtYXRPdXRwdXRJbnRcbiAqIEBwYXJhbSB7U29saWRpdHlQYXJhbX0gcGFyYW1cbiAqIEByZXR1cm5zIHtCaWdOdW1iZXJ9IHJpZ2h0LWFsaWduZWQgb3V0cHV0IGJ5dGVzIGZvcm1hdHRlZCB0byBiaWcgbnVtYmVyXG4gKi9cbnZhciBmb3JtYXRPdXRwdXRJbnQgPSBmdW5jdGlvbiAocGFyYW0pIHtcbiAgICB2YXIgdmFsdWUgPSBwYXJhbS5zdGF0aWNQYXJ0KCkgfHwgXCIwXCI7XG5cbiAgICAvLyBjaGVjayBpZiBpdCdzIG5lZ2F0aXZlIG51bWJlclxuICAgIC8vIGl0IGl0IGlzLCByZXR1cm4gdHdvJ3MgY29tcGxlbWVudFxuICAgIGlmIChzaWduZWRJc05lZ2F0aXZlKHZhbHVlKSkge1xuICAgICAgICByZXR1cm4gbmV3IEJpZ051bWJlcih2YWx1ZSwgMTYpLm1pbnVzKG5ldyBCaWdOdW1iZXIoJ2ZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmYnLCAxNikpLm1pbnVzKDEpO1xuICAgIH1cbiAgICByZXR1cm4gbmV3IEJpZ051bWJlcih2YWx1ZSwgMTYpO1xufTtcblxuLyoqXG4gKiBGb3JtYXRzIHJpZ2h0LWFsaWduZWQgb3V0cHV0IGJ5dGVzIHRvIHVpbnRcbiAqXG4gKiBAbWV0aG9kIGZvcm1hdE91dHB1dFVJbnRcbiAqIEBwYXJhbSB7U29saWRpdHlQYXJhbX1cbiAqIEByZXR1cm5zIHtCaWdOdW1lYmVyfSByaWdodC1hbGlnbmVkIG91dHB1dCBieXRlcyBmb3JtYXR0ZWQgdG8gdWludFxuICovXG52YXIgZm9ybWF0T3V0cHV0VUludCA9IGZ1bmN0aW9uIChwYXJhbSkge1xuICAgIHZhciB2YWx1ZSA9IHBhcmFtLnN0YXRpY1BhcnQoKSB8fCBcIjBcIjtcbiAgICByZXR1cm4gbmV3IEJpZ051bWJlcih2YWx1ZSwgMTYpO1xufTtcblxuLyoqXG4gKiBGb3JtYXRzIHJpZ2h0LWFsaWduZWQgb3V0cHV0IGJ5dGVzIHRvIHJlYWxcbiAqXG4gKiBAbWV0aG9kIGZvcm1hdE91dHB1dFJlYWxcbiAqIEBwYXJhbSB7U29saWRpdHlQYXJhbX1cbiAqIEByZXR1cm5zIHtCaWdOdW1iZXJ9IGlucHV0IGJ5dGVzIGZvcm1hdHRlZCB0byByZWFsXG4gKi9cbnZhciBmb3JtYXRPdXRwdXRSZWFsID0gZnVuY3Rpb24gKHBhcmFtKSB7XG4gICAgcmV0dXJuIGZvcm1hdE91dHB1dEludChwYXJhbSkuZGl2aWRlZEJ5KG5ldyBCaWdOdW1iZXIoMikucG93KDEyOCkpOyBcbn07XG5cbi8qKlxuICogRm9ybWF0cyByaWdodC1hbGlnbmVkIG91dHB1dCBieXRlcyB0byB1cmVhbFxuICpcbiAqIEBtZXRob2QgZm9ybWF0T3V0cHV0VVJlYWxcbiAqIEBwYXJhbSB7U29saWRpdHlQYXJhbX1cbiAqIEByZXR1cm5zIHtCaWdOdW1iZXJ9IGlucHV0IGJ5dGVzIGZvcm1hdHRlZCB0byB1cmVhbFxuICovXG52YXIgZm9ybWF0T3V0cHV0VVJlYWwgPSBmdW5jdGlvbiAocGFyYW0pIHtcbiAgICByZXR1cm4gZm9ybWF0T3V0cHV0VUludChwYXJhbSkuZGl2aWRlZEJ5KG5ldyBCaWdOdW1iZXIoMikucG93KDEyOCkpOyBcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZm9ybWF0IG91dHB1dCBib29sXG4gKlxuICogQG1ldGhvZCBmb3JtYXRPdXRwdXRCb29sXG4gKiBAcGFyYW0ge1NvbGlkaXR5UGFyYW19XG4gKiBAcmV0dXJucyB7Qm9vbGVhbn0gcmlnaHQtYWxpZ25lZCBpbnB1dCBieXRlcyBmb3JtYXR0ZWQgdG8gYm9vbFxuICovXG52YXIgZm9ybWF0T3V0cHV0Qm9vbCA9IGZ1bmN0aW9uIChwYXJhbSkge1xuICAgIHJldHVybiBwYXJhbS5zdGF0aWNQYXJ0KCkgPT09ICcwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAxJyA/IHRydWUgOiBmYWxzZTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZm9ybWF0IG91dHB1dCBzdHJpbmdcbiAqXG4gKiBAbWV0aG9kIGZvcm1hdE91dHB1dEJ5dGVzXG4gKiBAcGFyYW0ge1NvbGlkaXR5UGFyYW19IGxlZnQtYWxpZ25lZCBoZXggcmVwcmVzZW50YXRpb24gb2Ygc3RyaW5nXG4gKiBAcmV0dXJucyB7U3RyaW5nfSBhc2NpaSBzdHJpbmdcbiAqL1xudmFyIGZvcm1hdE91dHB1dEJ5dGVzID0gZnVuY3Rpb24gKHBhcmFtKSB7XG4gICAgLy8gbGVuZ3RoIG1pZ2h0IGFsc28gYmUgaW1wb3J0YW50IVxuICAgIHJldHVybiB1dGlscy50b0FzY2lpKHBhcmFtLnN0YXRpY1BhcnQoKSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGZvcm1hdCBvdXRwdXQgc3RyaW5nXG4gKlxuICogQG1ldGhvZCBmb3JtYXRPdXRwdXREeW5hbWljQnl0ZXNcbiAqIEBwYXJhbSB7U29saWRpdHlQYXJhbX0gbGVmdC1hbGlnbmVkIGhleCByZXByZXNlbnRhdGlvbiBvZiBzdHJpbmdcbiAqIEByZXR1cm5zIHtTdHJpbmd9IGFzY2lpIHN0cmluZ1xuICovXG52YXIgZm9ybWF0T3V0cHV0RHluYW1pY0J5dGVzID0gZnVuY3Rpb24gKHBhcmFtKSB7XG4gICAgLy8gbGVuZ3RoIG1pZ2h0IGFsc28gYmUgaW1wb3J0YW50IVxuICAgIHJldHVybiB1dGlscy50b0FzY2lpKHBhcmFtLmR5bmFtaWNQYXJ0KCkuc2xpY2UoNjQpKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZm9ybWF0IG91dHB1dCBhZGRyZXNzXG4gKlxuICogQG1ldGhvZCBmb3JtYXRPdXRwdXRBZGRyZXNzXG4gKiBAcGFyYW0ge1NvbGlkaXR5UGFyYW19IHJpZ2h0LWFsaWduZWQgaW5wdXQgYnl0ZXNcbiAqIEByZXR1cm5zIHtTdHJpbmd9IGFkZHJlc3NcbiAqL1xudmFyIGZvcm1hdE91dHB1dEFkZHJlc3MgPSBmdW5jdGlvbiAocGFyYW0pIHtcbiAgICB2YXIgdmFsdWUgPSBwYXJhbS5zdGF0aWNQYXJ0KCk7XG4gICAgcmV0dXJuIFwiMHhcIiArIHZhbHVlLnNsaWNlKHZhbHVlLmxlbmd0aCAtIDQwLCB2YWx1ZS5sZW5ndGgpO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgZm9ybWF0SW5wdXRJbnQ6IGZvcm1hdElucHV0SW50LFxuICAgIGZvcm1hdElucHV0Qnl0ZXM6IGZvcm1hdElucHV0Qnl0ZXMsXG4gICAgZm9ybWF0SW5wdXREeW5hbWljQnl0ZXM6IGZvcm1hdElucHV0RHluYW1pY0J5dGVzLFxuICAgIGZvcm1hdElucHV0Qm9vbDogZm9ybWF0SW5wdXRCb29sLFxuICAgIGZvcm1hdElucHV0UmVhbDogZm9ybWF0SW5wdXRSZWFsLFxuICAgIGZvcm1hdE91dHB1dEludDogZm9ybWF0T3V0cHV0SW50LFxuICAgIGZvcm1hdE91dHB1dFVJbnQ6IGZvcm1hdE91dHB1dFVJbnQsXG4gICAgZm9ybWF0T3V0cHV0UmVhbDogZm9ybWF0T3V0cHV0UmVhbCxcbiAgICBmb3JtYXRPdXRwdXRVUmVhbDogZm9ybWF0T3V0cHV0VVJlYWwsXG4gICAgZm9ybWF0T3V0cHV0Qm9vbDogZm9ybWF0T3V0cHV0Qm9vbCxcbiAgICBmb3JtYXRPdXRwdXRCeXRlczogZm9ybWF0T3V0cHV0Qnl0ZXMsXG4gICAgZm9ybWF0T3V0cHV0RHluYW1pY0J5dGVzOiBmb3JtYXRPdXRwdXREeW5hbWljQnl0ZXMsXG4gICAgZm9ybWF0T3V0cHV0QWRkcmVzczogZm9ybWF0T3V0cHV0QWRkcmVzc1xufTtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogXG4gKiBAZmlsZSBwYXJhbS5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy91dGlscycpO1xuXG4vKipcbiAqIFNvbGlkaXR5UGFyYW0gb2JqZWN0IHByb3RvdHlwZS5cbiAqIFNob3VsZCBiZSB1c2VkIHdoZW4gZW5jb2RpbmcsIGRlY29kaW5nIHNvbGlkaXR5IGJ5dGVzXG4gKi9cbnZhciBTb2xpZGl0eVBhcmFtID0gZnVuY3Rpb24gKHZhbHVlLCBvZmZzZXQpIHtcbiAgICB0aGlzLnZhbHVlID0gdmFsdWUgfHwgJyc7XG4gICAgdGhpcy5vZmZzZXQgPSBvZmZzZXQ7IC8vIG9mZnNldCBpbiBieXRlc1xufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgdXNlZCB0byBnZXQgbGVuZ3RoIG9mIHBhcmFtcydzIGR5bmFtaWMgcGFydFxuICogXG4gKiBAbWV0aG9kIGR5bmFtaWNQYXJ0TGVuZ3RoXG4gKiBAcmV0dXJucyB7TnVtYmVyfSBsZW5ndGggb2YgZHluYW1pYyBwYXJ0IChpbiBieXRlcylcbiAqL1xuU29saWRpdHlQYXJhbS5wcm90b3R5cGUuZHluYW1pY1BhcnRMZW5ndGggPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuZHluYW1pY1BhcnQoKS5sZW5ndGggLyAyO1xufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgdXNlZCB0byBjcmVhdGUgY29weSBvZiBzb2xpZGl0eSBwYXJhbSB3aXRoIGRpZmZlcmVudCBvZmZzZXRcbiAqXG4gKiBAbWV0aG9kIHdpdGhPZmZzZXRcbiAqIEBwYXJhbSB7TnVtYmVyfSBvZmZzZXQgbGVuZ3RoIGluIGJ5dGVzXG4gKiBAcmV0dXJucyB7U29saWRpdHlQYXJhbX0gbmV3IHNvbGlkaXR5IHBhcmFtIHdpdGggYXBwbGllZCBvZmZzZXRcbiAqL1xuU29saWRpdHlQYXJhbS5wcm90b3R5cGUud2l0aE9mZnNldCA9IGZ1bmN0aW9uIChvZmZzZXQpIHtcbiAgICByZXR1cm4gbmV3IFNvbGlkaXR5UGFyYW0odGhpcy52YWx1ZSwgb2Zmc2V0KTtcbn07XG5cbi8qKlxuICogVGhpcyBtZXRob2Qgc2hvdWxkIGJlIHVzZWQgdG8gY29tYmluZSBzb2xpZGl0eSBwYXJhbXMgdG9nZXRoZXJcbiAqIGVnLiB3aGVuIGFwcGVuZGluZyBhbiBhcnJheVxuICpcbiAqIEBtZXRob2QgY29tYmluZVxuICogQHBhcmFtIHtTb2xpZGl0eVBhcmFtfSBwYXJhbSB3aXRoIHdoaWNoIHdlIHNob3VsZCBjb21iaW5lXG4gKiBAcGFyYW0ge1NvbGlkaXR5UGFyYW19IHJlc3VsdCBvZiBjb21iaW5hdGlvblxuICovXG5Tb2xpZGl0eVBhcmFtLnByb3RvdHlwZS5jb21iaW5lID0gZnVuY3Rpb24gKHBhcmFtKSB7XG4gICAgcmV0dXJuIG5ldyBTb2xpZGl0eVBhcmFtKHRoaXMudmFsdWUgKyBwYXJhbS52YWx1ZSk7IFxufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgY2FsbGVkIHRvIGNoZWNrIGlmIHBhcmFtIGhhcyBkeW5hbWljIHNpemUuXG4gKiBJZiBpdCBoYXMsIGl0IHJldHVybnMgdHJ1ZSwgb3RoZXJ3aXNlIGZhbHNlXG4gKlxuICogQG1ldGhvZCBpc0R5bmFtaWNcbiAqIEByZXR1cm5zIHtCb29sZWFufVxuICovXG5Tb2xpZGl0eVBhcmFtLnByb3RvdHlwZS5pc0R5bmFtaWMgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMudmFsdWUubGVuZ3RoID4gNjQgfHwgdGhpcy5vZmZzZXQgIT09IHVuZGVmaW5lZDtcbn07XG5cbi8qKlxuICogVGhpcyBtZXRob2Qgc2hvdWxkIGJlIGNhbGxlZCB0byB0cmFuc2Zvcm0gb2Zmc2V0IHRvIGJ5dGVzXG4gKlxuICogQG1ldGhvZCBvZmZzZXRBc0J5dGVzXG4gKiBAcmV0dXJucyB7U3RyaW5nfSBieXRlcyByZXByZXNlbnRhdGlvbiBvZiBvZmZzZXRcbiAqL1xuU29saWRpdHlQYXJhbS5wcm90b3R5cGUub2Zmc2V0QXNCeXRlcyA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gIXRoaXMuaXNEeW5hbWljKCkgPyAnJyA6IHV0aWxzLnBhZExlZnQodXRpbHMudG9Ud29zQ29tcGxlbWVudCh0aGlzLm9mZnNldCkudG9TdHJpbmcoMTYpLCA2NCk7XG59O1xuXG4vKipcbiAqIFRoaXMgbWV0aG9kIHNob3VsZCBiZSBjYWxsZWQgdG8gZ2V0IHN0YXRpYyBwYXJ0IG9mIHBhcmFtXG4gKlxuICogQG1ldGhvZCBzdGF0aWNQYXJ0XG4gKiBAcmV0dXJucyB7U3RyaW5nfSBvZmZzZXQgaWYgaXQgaXMgYSBkeW5hbWljIHBhcmFtLCBvdGhlcndpc2UgdmFsdWVcbiAqL1xuU29saWRpdHlQYXJhbS5wcm90b3R5cGUuc3RhdGljUGFydCA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoIXRoaXMuaXNEeW5hbWljKCkpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWU7IFxuICAgIH0gXG4gICAgcmV0dXJuIHRoaXMub2Zmc2V0QXNCeXRlcygpO1xufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgY2FsbGVkIHRvIGdldCBkeW5hbWljIHBhcnQgb2YgcGFyYW1cbiAqXG4gKiBAbWV0aG9kIGR5bmFtaWNQYXJ0XG4gKiBAcmV0dXJucyB7U3RyaW5nfSByZXR1cm5zIGEgdmFsdWUgaWYgaXQgaXMgYSBkeW5hbWljIHBhcmFtLCBvdGhlcndpc2UgZW1wdHkgc3RyaW5nXG4gKi9cblNvbGlkaXR5UGFyYW0ucHJvdG90eXBlLmR5bmFtaWNQYXJ0ID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLmlzRHluYW1pYygpID8gdGhpcy52YWx1ZSA6ICcnO1xufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgY2FsbGVkIHRvIGVuY29kZSBwYXJhbVxuICpcbiAqIEBtZXRob2QgZW5jb2RlXG4gKiBAcmV0dXJucyB7U3RyaW5nfVxuICovXG5Tb2xpZGl0eVBhcmFtLnByb3RvdHlwZS5lbmNvZGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGljUGFydCgpICsgdGhpcy5keW5hbWljUGFydCgpO1xufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgY2FsbGVkIHRvIGVuY29kZSBhcnJheSBvZiBwYXJhbXNcbiAqXG4gKiBAbWV0aG9kIGVuY29kZUxpc3RcbiAqIEBwYXJhbSB7QXJyYXlbU29saWRpdHlQYXJhbV19IHBhcmFtc1xuICogQHJldHVybnMge1N0cmluZ31cbiAqL1xuU29saWRpdHlQYXJhbS5lbmNvZGVMaXN0ID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICAgIFxuICAgIC8vIHVwZGF0aW5nIG9mZnNldHNcbiAgICB2YXIgdG90YWxPZmZzZXQgPSBwYXJhbXMubGVuZ3RoICogMzI7XG4gICAgdmFyIG9mZnNldFBhcmFtcyA9IHBhcmFtcy5tYXAoZnVuY3Rpb24gKHBhcmFtKSB7XG4gICAgICAgIGlmICghcGFyYW0uaXNEeW5hbWljKCkpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXJhbTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgb2Zmc2V0ID0gdG90YWxPZmZzZXQ7XG4gICAgICAgIHRvdGFsT2Zmc2V0ICs9IHBhcmFtLmR5bmFtaWNQYXJ0TGVuZ3RoKCk7XG4gICAgICAgIHJldHVybiBwYXJhbS53aXRoT2Zmc2V0KG9mZnNldCk7XG4gICAgfSk7XG5cbiAgICAvLyBlbmNvZGUgZXZlcnl0aGluZyFcbiAgICByZXR1cm4gb2Zmc2V0UGFyYW1zLnJlZHVjZShmdW5jdGlvbiAocmVzdWx0LCBwYXJhbSkge1xuICAgICAgICByZXR1cm4gcmVzdWx0ICsgcGFyYW0uZHluYW1pY1BhcnQoKTtcbiAgICB9LCBvZmZzZXRQYXJhbXMucmVkdWNlKGZ1bmN0aW9uIChyZXN1bHQsIHBhcmFtKSB7XG4gICAgICAgIHJldHVybiByZXN1bHQgKyBwYXJhbS5zdGF0aWNQYXJ0KCk7XG4gICAgfSwgJycpKTtcbn07XG5cbi8qKlxuICogVGhpcyBtZXRob2Qgc2hvdWxkIGJlIHVzZWQgdG8gZGVjb2RlIHBsYWluIChzdGF0aWMpIHNvbGlkaXR5IHBhcmFtIGF0IGdpdmVuIGluZGV4XG4gKlxuICogQG1ldGhvZCBkZWNvZGVQYXJhbVxuICogQHBhcmFtIHtTdHJpbmd9IGJ5dGVzXG4gKiBAcGFyYW0ge051bWJlcn0gaW5kZXhcbiAqIEByZXR1cm5zIHtTb2xpZGl0eVBhcmFtfVxuICovXG5Tb2xpZGl0eVBhcmFtLmRlY29kZVBhcmFtID0gZnVuY3Rpb24gKGJ5dGVzLCBpbmRleCkge1xuICAgIGluZGV4ID0gaW5kZXggfHwgMDtcbiAgICByZXR1cm4gbmV3IFNvbGlkaXR5UGFyYW0oYnl0ZXMuc3Vic3RyKGluZGV4ICogNjQsIDY0KSk7IFxufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgY2FsbGVkIHRvIGdldCBvZmZzZXQgdmFsdWUgZnJvbSBieXRlcyBhdCBnaXZlbiBpbmRleFxuICpcbiAqIEBtZXRob2QgZ2V0T2Zmc2V0XG4gKiBAcGFyYW0ge1N0cmluZ30gYnl0ZXNcbiAqIEBwYXJhbSB7TnVtYmVyfSBpbmRleFxuICogQHJldHVybnMge051bWJlcn0gb2Zmc2V0IGFzIG51bWJlclxuICovXG52YXIgZ2V0T2Zmc2V0ID0gZnVuY3Rpb24gKGJ5dGVzLCBpbmRleCkge1xuICAgIC8vIHdlIGNhbiBkbyB0aGlzIGNhdXNlIG9mZnNldCBpcyByYXRoZXIgc21hbGxcbiAgICByZXR1cm4gcGFyc2VJbnQoJzB4JyArIGJ5dGVzLnN1YnN0cihpbmRleCAqIDY0LCA2NCkpO1xufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgY2FsbGVkIHRvIGRlY29kZSBzb2xpZGl0eSBieXRlcyBwYXJhbSBhdCBnaXZlbiBpbmRleFxuICpcbiAqIEBtZXRob2QgZGVjb2RlQnl0ZXNcbiAqIEBwYXJhbSB7U3RyaW5nfSBieXRlc1xuICogQHBhcmFtIHtOdW1iZXJ9IGluZGV4XG4gKiBAcmV0dXJucyB7U29saWRpdHlQYXJhbX1cbiAqL1xuU29saWRpdHlQYXJhbS5kZWNvZGVCeXRlcyA9IGZ1bmN0aW9uIChieXRlcywgaW5kZXgpIHtcbiAgICBpbmRleCA9IGluZGV4IHx8IDA7XG4gICAgLy9UT0RPIGFkZCBzdXBwb3J0IGZvciBzdHJpbmdzIGxvbmdlciB0aGFuIDMyIGJ5dGVzXG4gICAgLy92YXIgbGVuZ3RoID0gcGFyc2VJbnQoJzB4JyArIGJ5dGVzLnN1YnN0cihvZmZzZXQgKiA2NCwgNjQpKTtcblxuICAgIHZhciBvZmZzZXQgPSBnZXRPZmZzZXQoYnl0ZXMsIGluZGV4KTtcblxuICAgIC8vIDIgKiAsIGNhdXNlIHdlIGFsc28gcGFyc2UgbGVuZ3RoXG4gICAgcmV0dXJuIG5ldyBTb2xpZGl0eVBhcmFtKGJ5dGVzLnN1YnN0cihvZmZzZXQgKiAyLCAyICogNjQpLCAwKTtcbn07XG5cbi8qKlxuICogVGhpcyBtZXRob2Qgc2hvdWxkIGJlIHVzZWQgdG8gZGVjb2RlIHNvbGlkaXR5IGFycmF5IGF0IGdpdmVuIGluZGV4XG4gKlxuICogQG1ldGhvZCBkZWNvZGVBcnJheVxuICogQHBhcmFtIHtTdHJpbmd9IGJ5dGVzXG4gKiBAcGFyYW0ge051bWJlcn0gaW5kZXhcbiAqIEByZXR1cm5zIHtTb2xpZGl0eVBhcmFtfVxuICovXG5Tb2xpZGl0eVBhcmFtLmRlY29kZUFycmF5ID0gZnVuY3Rpb24gKGJ5dGVzLCBpbmRleCkge1xuICAgIGluZGV4ID0gaW5kZXggfHwgMDtcbiAgICB2YXIgb2Zmc2V0ID0gZ2V0T2Zmc2V0KGJ5dGVzLCBpbmRleCk7XG4gICAgdmFyIGxlbmd0aCA9IHBhcnNlSW50KCcweCcgKyBieXRlcy5zdWJzdHIob2Zmc2V0ICogMiwgNjQpKTtcbiAgICByZXR1cm4gbmV3IFNvbGlkaXR5UGFyYW0oYnl0ZXMuc3Vic3RyKG9mZnNldCAqIDIsIChsZW5ndGggKyAxKSAqIDY0KSwgMCk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFNvbGlkaXR5UGFyYW07XG5cbiIsIid1c2Ugc3RyaWN0JztcblxuLy8gZ28gZW52IGRvZXNuJ3QgaGF2ZSBhbmQgbmVlZCBYTUxIdHRwUmVxdWVzdFxuaWYgKHR5cGVvZiBYTUxIdHRwUmVxdWVzdCA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBleHBvcnRzLlhNTEh0dHBSZXF1ZXN0ID0ge307XG59IGVsc2Uge1xuICAgIGV4cG9ydHMuWE1MSHR0cFJlcXVlc3QgPSBYTUxIdHRwUmVxdWVzdDsgLy8ganNoaW50IGlnbm9yZTpsaW5lXG59XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqIEBmaWxlIGNvbmZpZy5qc1xuICogQGF1dGhvcnM6XG4gKiAgIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbi8qKlxuICogVXRpbHNcbiAqIFxuICogQG1vZHVsZSB1dGlsc1xuICovXG5cbi8qKlxuICogVXRpbGl0eSBmdW5jdGlvbnNcbiAqIFxuICogQGNsYXNzIFt1dGlsc10gY29uZmlnXG4gKiBAY29uc3RydWN0b3JcbiAqL1xuXG4vLy8gcmVxdWlyZWQgdG8gZGVmaW5lIEVUSF9CSUdOVU1CRVJfUk9VTkRJTkdfTU9ERVxudmFyIEJpZ051bWJlciA9IHJlcXVpcmUoJ2JpZ251bWJlci5qcycpO1xuXG52YXIgRVRIX1VOSVRTID0gW1xuICAgICd3ZWknLFxuICAgICdrd2VpJyxcbiAgICAnTXdlaScsXG4gICAgJ0d3ZWknLFxuICAgICdzemFibycsXG4gICAgJ2Zpbm5leScsXG4gICAgJ2ZlbXRvZXRoZXInLFxuICAgICdwaWNvZXRoZXInLFxuICAgICduYW5vZXRoZXInLFxuICAgICdtaWNyb2V0aGVyJyxcbiAgICAnbWlsbGlldGhlcicsXG4gICAgJ25hbm8nLFxuICAgICdtaWNybycsXG4gICAgJ21pbGxpJyxcbiAgICAnZXRoZXInLFxuICAgICdncmFuZCcsXG4gICAgJ01ldGhlcicsXG4gICAgJ0dldGhlcicsXG4gICAgJ1RldGhlcicsXG4gICAgJ1BldGhlcicsXG4gICAgJ0VldGhlcicsXG4gICAgJ1pldGhlcicsXG4gICAgJ1lldGhlcicsXG4gICAgJ05ldGhlcicsXG4gICAgJ0RldGhlcicsXG4gICAgJ1ZldGhlcicsXG4gICAgJ1VldGhlcidcbl07XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIEVUSF9QQURESU5HOiAzMixcbiAgICBFVEhfU0lHTkFUVVJFX0xFTkdUSDogNCxcbiAgICBFVEhfVU5JVFM6IEVUSF9VTklUUyxcbiAgICBFVEhfQklHTlVNQkVSX1JPVU5ESU5HX01PREU6IHsgUk9VTkRJTkdfTU9ERTogQmlnTnVtYmVyLlJPVU5EX0RPV04gfSxcbiAgICBFVEhfUE9MTElOR19USU1FT1VUOiAxMDAwLFxuICAgIGRlZmF1bHRCbG9jazogJ2xhdGVzdCcsXG4gICAgZGVmYXVsdEFjY291bnQ6IHVuZGVmaW5lZFxufTtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogXG4gKiBAZmlsZSBzaGEzLmpzXG4gKiBAYXV0aG9yIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbnZhciB1dGlscyA9IHJlcXVpcmUoJy4vdXRpbHMnKTtcbnZhciBzaGEzID0gcmVxdWlyZSgnY3J5cHRvLWpzL3NoYTMnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoc3RyLCBpc05ldykge1xuICAgIGlmIChzdHIuc3Vic3RyKDAsIDIpID09PSAnMHgnICYmICFpc05ldykge1xuICAgICAgICBjb25zb2xlLndhcm4oJ3JlcXVpcmVtZW50IG9mIHVzaW5nIHdlYjMuZnJvbUFzY2lpIGJlZm9yZSBzaGEzIGlzIGRlcHJlY2F0ZWQnKTtcbiAgICAgICAgY29uc29sZS53YXJuKCduZXcgdXNhZ2U6IFxcJ3dlYjMuc2hhMyhcImhlbGxvXCIpXFwnJyk7XG4gICAgICAgIGNvbnNvbGUud2Fybignc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9ldGhlcmV1bS93ZWIzLmpzL3B1bGwvMjA1Jyk7XG4gICAgICAgIGNvbnNvbGUud2FybignaWYgeW91IG5lZWQgdG8gaGFzaCBoZXggdmFsdWUsIHlvdSBjYW4gZG8gXFwnc2hhMyhcIjB4ZmZmXCIsIHRydWUpXFwnJyk7XG4gICAgICAgIHN0ciA9IHV0aWxzLnRvQXNjaWkoc3RyKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc2hhMyhzdHIsIHtcbiAgICAgICAgb3V0cHV0TGVuZ3RoOiAyNTZcbiAgICB9KS50b1N0cmluZygpO1xufTtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogXG4gKiBAZmlsZSB1dGlscy5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG4vKipcbiAqIFV0aWxzXG4gKiBcbiAqIEBtb2R1bGUgdXRpbHNcbiAqL1xuXG4vKipcbiAqIFV0aWxpdHkgZnVuY3Rpb25zXG4gKiBcbiAqIEBjbGFzcyBbdXRpbHNdIHV0aWxzXG4gKiBAY29uc3RydWN0b3JcbiAqL1xuXG52YXIgQmlnTnVtYmVyID0gcmVxdWlyZSgnYmlnbnVtYmVyLmpzJyk7XG5cbnZhciB1bml0TWFwID0ge1xuICAgICd3ZWknOiAgICAgICAgICAnMScsXG4gICAgJ2t3ZWknOiAgICAgICAgICcxMDAwJyxcbiAgICAnYWRhJzogICAgICAgICAgJzEwMDAnLFxuICAgICdmZW10b2V0aGVyJzogICAnMTAwMCcsXG4gICAgJ213ZWknOiAgICAgICAgICcxMDAwMDAwJyxcbiAgICAnYmFiYmFnZSc6ICAgICAgJzEwMDAwMDAnLFxuICAgICdwaWNvZXRoZXInOiAgICAnMTAwMDAwMCcsXG4gICAgJ2d3ZWknOiAgICAgICAgICcxMDAwMDAwMDAwJyxcbiAgICAnc2hhbm5vbic6ICAgICAgJzEwMDAwMDAwMDAnLFxuICAgICduYW5vZXRoZXInOiAgICAnMTAwMDAwMDAwMCcsXG4gICAgJ25hbm8nOiAgICAgICAgICcxMDAwMDAwMDAwJyxcbiAgICAnc3phYm8nOiAgICAgICAgJzEwMDAwMDAwMDAwMDAnLFxuICAgICdtaWNyb2V0aGVyJzogICAnMTAwMDAwMDAwMDAwMCcsXG4gICAgJ21pY3JvJzogICAgICAgICcxMDAwMDAwMDAwMDAwJyxcbiAgICAnZmlubmV5JzogICAgICAgJzEwMDAwMDAwMDAwMDAwMDAnLFxuICAgICdtaWxsaWV0aGVyJzogICAgJzEwMDAwMDAwMDAwMDAwMDAnLFxuICAgICdtaWxsaSc6ICAgICAgICAgJzEwMDAwMDAwMDAwMDAwMDAnLFxuICAgICdldGhlcic6ICAgICAgICAnMTAwMDAwMDAwMDAwMDAwMDAwMCcsXG4gICAgJ2tldGhlcic6ICAgICAgICcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwJyxcbiAgICAnZ3JhbmQnOiAgICAgICAgJzEwMDAwMDAwMDAwMDAwMDAwMDAwMDAnLFxuICAgICdlaW5zdGVpbic6ICAgICAnMTAwMDAwMDAwMDAwMDAwMDAwMDAwMCcsXG4gICAgJ21ldGhlcic6ICAgICAgICcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwJyxcbiAgICAnZ2V0aGVyJzogICAgICAgJzEwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAnLFxuICAgICd0ZXRoZXInOiAgICAgICAnMTAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMCdcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBwYWQgc3RyaW5nIHRvIGV4cGVjdGVkIGxlbmd0aFxuICpcbiAqIEBtZXRob2QgcGFkTGVmdFxuICogQHBhcmFtIHtTdHJpbmd9IHN0cmluZyB0byBiZSBwYWRkZWRcbiAqIEBwYXJhbSB7TnVtYmVyfSBjaGFyYWN0ZXJzIHRoYXQgcmVzdWx0IHN0cmluZyBzaG91bGQgaGF2ZVxuICogQHBhcmFtIHtTdHJpbmd9IHNpZ24sIGJ5IGRlZmF1bHQgMFxuICogQHJldHVybnMge1N0cmluZ30gcmlnaHQgYWxpZ25lZCBzdHJpbmdcbiAqL1xudmFyIHBhZExlZnQgPSBmdW5jdGlvbiAoc3RyaW5nLCBjaGFycywgc2lnbikge1xuICAgIHJldHVybiBuZXcgQXJyYXkoY2hhcnMgLSBzdHJpbmcubGVuZ3RoICsgMSkuam9pbihzaWduID8gc2lnbiA6IFwiMFwiKSArIHN0cmluZztcbn07XG5cbi8qKiBcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZ2V0IHN0aW5nIGZyb20gaXQncyBoZXggcmVwcmVzZW50YXRpb25cbiAqXG4gKiBAbWV0aG9kIHRvQXNjaWlcbiAqIEBwYXJhbSB7U3RyaW5nfSBzdHJpbmcgaW4gaGV4XG4gKiBAcmV0dXJucyB7U3RyaW5nfSBhc2NpaSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgaGV4IHZhbHVlXG4gKi9cbnZhciB0b0FzY2lpID0gZnVuY3Rpb24oaGV4KSB7XG4vLyBGaW5kIHRlcm1pbmF0aW9uXG4gICAgdmFyIHN0ciA9IFwiXCI7XG4gICAgdmFyIGkgPSAwLCBsID0gaGV4Lmxlbmd0aDtcbiAgICBpZiAoaGV4LnN1YnN0cmluZygwLCAyKSA9PT0gJzB4Jykge1xuICAgICAgICBpID0gMjtcbiAgICB9XG4gICAgZm9yICg7IGkgPCBsOyBpKz0yKSB7XG4gICAgICAgIHZhciBjb2RlID0gcGFyc2VJbnQoaGV4LnN1YnN0cihpLCAyKSwgMTYpO1xuICAgICAgICBpZiAoY29kZSA9PT0gMCkge1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cblxuICAgICAgICBzdHIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShjb2RlKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc3RyO1xufTtcbiAgICBcbi8qKlxuICogU2hvbGQgYmUgY2FsbGVkIHRvIGdldCBoZXggcmVwcmVzZW50YXRpb24gKHByZWZpeGVkIGJ5IDB4KSBvZiBhc2NpaSBzdHJpbmcgXG4gKlxuICogQG1ldGhvZCB0b0hleE5hdGl2ZVxuICogQHBhcmFtIHtTdHJpbmd9IHN0cmluZ1xuICogQHJldHVybnMge1N0cmluZ30gaGV4IHJlcHJlc2VudGF0aW9uIG9mIGlucHV0IHN0cmluZ1xuICovXG52YXIgdG9IZXhOYXRpdmUgPSBmdW5jdGlvbihzdHIpIHtcbiAgICB2YXIgaGV4ID0gXCJcIjtcbiAgICBmb3IodmFyIGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBuID0gc3RyLmNoYXJDb2RlQXQoaSkudG9TdHJpbmcoMTYpO1xuICAgICAgICBoZXggKz0gbi5sZW5ndGggPCAyID8gJzAnICsgbiA6IG47XG4gICAgfVxuXG4gICAgcmV0dXJuIGhleDtcbn07XG5cbi8qKlxuICogU2hvbGQgYmUgY2FsbGVkIHRvIGdldCBoZXggcmVwcmVzZW50YXRpb24gKHByZWZpeGVkIGJ5IDB4KSBvZiBhc2NpaSBzdHJpbmcgXG4gKlxuICogQG1ldGhvZCBmcm9tQXNjaWlcbiAqIEBwYXJhbSB7U3RyaW5nfSBzdHJpbmdcbiAqIEBwYXJhbSB7TnVtYmVyfSBvcHRpb25hbCBwYWRkaW5nXG4gKiBAcmV0dXJucyB7U3RyaW5nfSBoZXggcmVwcmVzZW50YXRpb24gb2YgaW5wdXQgc3RyaW5nXG4gKi9cbnZhciBmcm9tQXNjaWkgPSBmdW5jdGlvbihzdHIsIHBhZCkge1xuICAgIHBhZCA9IHBhZCA9PT0gdW5kZWZpbmVkID8gMCA6IHBhZDtcbiAgICB2YXIgaGV4ID0gdG9IZXhOYXRpdmUoc3RyKTtcbiAgICB3aGlsZSAoaGV4Lmxlbmd0aCA8IHBhZCoyKVxuICAgICAgICBoZXggKz0gXCIwMFwiO1xuICAgIHJldHVybiBcIjB4XCIgKyBoZXg7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGNyZWF0ZSBmdWxsIGZ1bmN0aW9uL2V2ZW50IG5hbWUgZnJvbSBqc29uIGFiaVxuICpcbiAqIEBtZXRob2QgdHJhbnNmb3JtVG9GdWxsTmFtZVxuICogQHBhcmFtIHtPYmplY3R9IGpzb24tYWJpXG4gKiBAcmV0dXJuIHtTdHJpbmd9IGZ1bGwgZm5jdGlvbi9ldmVudCBuYW1lXG4gKi9cbnZhciB0cmFuc2Zvcm1Ub0Z1bGxOYW1lID0gZnVuY3Rpb24gKGpzb24pIHtcbiAgICBpZiAoanNvbi5uYW1lLmluZGV4T2YoJygnKSAhPT0gLTEpIHtcbiAgICAgICAgcmV0dXJuIGpzb24ubmFtZTtcbiAgICB9XG5cbiAgICB2YXIgdHlwZU5hbWUgPSBqc29uLmlucHV0cy5tYXAoZnVuY3Rpb24oaSl7cmV0dXJuIGkudHlwZTsgfSkuam9pbigpO1xuICAgIHJldHVybiBqc29uLm5hbWUgKyAnKCcgKyB0eXBlTmFtZSArICcpJztcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBnZXQgZGlzcGxheSBuYW1lIG9mIGNvbnRyYWN0IGZ1bmN0aW9uXG4gKiBcbiAqIEBtZXRob2QgZXh0cmFjdERpc3BsYXlOYW1lXG4gKiBAcGFyYW0ge1N0cmluZ30gbmFtZSBvZiBmdW5jdGlvbi9ldmVudFxuICogQHJldHVybnMge1N0cmluZ30gZGlzcGxheSBuYW1lIGZvciBmdW5jdGlvbi9ldmVudCBlZy4gbXVsdGlwbHkodWludDI1NikgLT4gbXVsdGlwbHlcbiAqL1xudmFyIGV4dHJhY3REaXNwbGF5TmFtZSA9IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgdmFyIGxlbmd0aCA9IG5hbWUuaW5kZXhPZignKCcpOyBcbiAgICByZXR1cm4gbGVuZ3RoICE9PSAtMSA/IG5hbWUuc3Vic3RyKDAsIGxlbmd0aCkgOiBuYW1lO1xufTtcblxuLy8vIEByZXR1cm5zIG92ZXJsb2FkZWQgcGFydCBvZiBmdW5jdGlvbi9ldmVudCBuYW1lXG52YXIgZXh0cmFjdFR5cGVOYW1lID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAvLy8gVE9ETzogbWFrZSBpdCBpbnZ1bG5lcmFibGVcbiAgICB2YXIgbGVuZ3RoID0gbmFtZS5pbmRleE9mKCcoJyk7XG4gICAgcmV0dXJuIGxlbmd0aCAhPT0gLTEgPyBuYW1lLnN1YnN0cihsZW5ndGggKyAxLCBuYW1lLmxlbmd0aCAtIDEgLSAobGVuZ3RoICsgMSkpLnJlcGxhY2UoJyAnLCAnJykgOiBcIlwiO1xufTtcblxuLyoqXG4gKiBDb252ZXJ0cyB2YWx1ZSB0byBpdCdzIGRlY2ltYWwgcmVwcmVzZW50YXRpb24gaW4gc3RyaW5nXG4gKlxuICogQG1ldGhvZCB0b0RlY2ltYWxcbiAqIEBwYXJhbSB7U3RyaW5nfE51bWJlcnxCaWdOdW1iZXJ9XG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKi9cbnZhciB0b0RlY2ltYWwgPSBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICByZXR1cm4gdG9CaWdOdW1iZXIodmFsdWUpLnRvTnVtYmVyKCk7XG59O1xuXG4vKipcbiAqIENvbnZlcnRzIHZhbHVlIHRvIGl0J3MgaGV4IHJlcHJlc2VudGF0aW9uXG4gKlxuICogQG1ldGhvZCBmcm9tRGVjaW1hbFxuICogQHBhcmFtIHtTdHJpbmd8TnVtYmVyfEJpZ051bWJlcn1cbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xudmFyIGZyb21EZWNpbWFsID0gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgdmFyIG51bWJlciA9IHRvQmlnTnVtYmVyKHZhbHVlKTtcbiAgICB2YXIgcmVzdWx0ID0gbnVtYmVyLnRvU3RyaW5nKDE2KTtcblxuICAgIHJldHVybiBudW1iZXIubGVzc1RoYW4oMCkgPyAnLTB4JyArIHJlc3VsdC5zdWJzdHIoMSkgOiAnMHgnICsgcmVzdWx0O1xufTtcblxuLyoqXG4gKiBBdXRvIGNvbnZlcnRzIGFueSBnaXZlbiB2YWx1ZSBpbnRvIGl0J3MgaGV4IHJlcHJlc2VudGF0aW9uLlxuICpcbiAqIEFuZCBldmVuIHN0cmluZ2lmeXMgb2JqZWN0cyBiZWZvcmUuXG4gKlxuICogQG1ldGhvZCB0b0hleFxuICogQHBhcmFtIHtTdHJpbmd8TnVtYmVyfEJpZ051bWJlcnxPYmplY3R9XG4gKiBAcmV0dXJuIHtTdHJpbmd9XG4gKi9cbnZhciB0b0hleCA9IGZ1bmN0aW9uICh2YWwpIHtcbiAgICAvKmpzaGludCBtYXhjb21wbGV4aXR5OjcgKi9cblxuICAgIGlmIChpc0Jvb2xlYW4odmFsKSlcbiAgICAgICAgcmV0dXJuIGZyb21EZWNpbWFsKCt2YWwpO1xuXG4gICAgaWYgKGlzQmlnTnVtYmVyKHZhbCkpXG4gICAgICAgIHJldHVybiBmcm9tRGVjaW1hbCh2YWwpO1xuXG4gICAgaWYgKGlzT2JqZWN0KHZhbCkpXG4gICAgICAgIHJldHVybiBmcm9tQXNjaWkoSlNPTi5zdHJpbmdpZnkodmFsKSk7XG5cbiAgICAvLyBpZiBpdHMgYSBuZWdhdGl2ZSBudW1iZXIsIHBhc3MgaXQgdGhyb3VnaCBmcm9tRGVjaW1hbFxuICAgIGlmIChpc1N0cmluZyh2YWwpKSB7XG4gICAgICAgIGlmICh2YWwuaW5kZXhPZignLTB4JykgPT09IDApXG4gICAgICAgICAgIHJldHVybiBmcm9tRGVjaW1hbCh2YWwpO1xuICAgICAgICBlbHNlIGlmICghaXNGaW5pdGUodmFsKSlcbiAgICAgICAgICAgIHJldHVybiBmcm9tQXNjaWkodmFsKTtcbiAgICB9XG5cbiAgICByZXR1cm4gZnJvbURlY2ltYWwodmFsKTtcbn07XG5cbi8qKlxuICogUmV0dXJucyB2YWx1ZSBvZiB1bml0IGluIFdlaVxuICpcbiAqIEBtZXRob2QgZ2V0VmFsdWVPZlVuaXRcbiAqIEBwYXJhbSB7U3RyaW5nfSB1bml0IHRoZSB1bml0IHRvIGNvbnZlcnQgdG8sIGRlZmF1bHQgZXRoZXJcbiAqIEByZXR1cm5zIHtCaWdOdW1iZXJ9IHZhbHVlIG9mIHRoZSB1bml0IChpbiBXZWkpXG4gKiBAdGhyb3dzIGVycm9yIGlmIHRoZSB1bml0IGlzIG5vdCBjb3JyZWN0OndcbiAqL1xudmFyIGdldFZhbHVlT2ZVbml0ID0gZnVuY3Rpb24gKHVuaXQpIHtcbiAgICB1bml0ID0gdW5pdCA/IHVuaXQudG9Mb3dlckNhc2UoKSA6ICdldGhlcic7XG4gICAgdmFyIHVuaXRWYWx1ZSA9IHVuaXRNYXBbdW5pdF07XG4gICAgaWYgKHVuaXRWYWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVGhpcyB1bml0IGRvZXNuXFwndCBleGlzdHMsIHBsZWFzZSB1c2UgdGhlIG9uZSBvZiB0aGUgZm9sbG93aW5nIHVuaXRzJyArIEpTT04uc3RyaW5naWZ5KHVuaXRNYXAsIG51bGwsIDIpKTtcbiAgICB9XG4gICAgcmV0dXJuIG5ldyBCaWdOdW1iZXIodW5pdFZhbHVlLCAxMCk7XG59O1xuXG4vKipcbiAqIFRha2VzIGEgbnVtYmVyIG9mIHdlaSBhbmQgY29udmVydHMgaXQgdG8gYW55IG90aGVyIGV0aGVyIHVuaXQuXG4gKlxuICogUG9zc2libGUgdW5pdHMgYXJlOlxuICogICBTSSBTaG9ydCAgIFNJIEZ1bGwgICAgICAgIEVmZmlneSAgICAgICBPdGhlclxuICogLSBrd2VpICAgICAgIGZlbXRvZXRoZXIgICAgIGFkYVxuICogLSBtd2VpICAgICAgIHBpY29ldGhlciAgICAgIGJhYmJhZ2VcbiAqIC0gZ3dlaSAgICAgICBuYW5vZXRoZXIgICAgICBzaGFubm9uICAgICAgbmFub1xuICogLSAtLSAgICAgICAgIG1pY3JvZXRoZXIgICAgIHN6YWJvICAgICAgICBtaWNyb1xuICogLSAtLSAgICAgICAgIG1pbGxpZXRoZXIgICAgIGZpbm5leSAgICAgICBtaWxsaVxuICogLSBldGhlciAgICAgIC0tICAgICAgICAgICAgIC0tXG4gKiAtIGtldGhlciAgICAgICAgICAgICAgICAgICAgZWluc3RlaW4gICAgIGdyYW5kIFxuICogLSBtZXRoZXJcbiAqIC0gZ2V0aGVyXG4gKiAtIHRldGhlclxuICpcbiAqIEBtZXRob2QgZnJvbVdlaVxuICogQHBhcmFtIHtOdW1iZXJ8U3RyaW5nfSBudW1iZXIgY2FuIGJlIGEgbnVtYmVyLCBudW1iZXIgc3RyaW5nIG9yIGEgSEVYIG9mIGEgZGVjaW1hbFxuICogQHBhcmFtIHtTdHJpbmd9IHVuaXQgdGhlIHVuaXQgdG8gY29udmVydCB0bywgZGVmYXVsdCBldGhlclxuICogQHJldHVybiB7U3RyaW5nfE9iamVjdH0gV2hlbiBnaXZlbiBhIEJpZ051bWJlciBvYmplY3QgaXQgcmV0dXJucyBvbmUgYXMgd2VsbCwgb3RoZXJ3aXNlIGEgbnVtYmVyXG4qL1xudmFyIGZyb21XZWkgPSBmdW5jdGlvbihudW1iZXIsIHVuaXQpIHtcbiAgICB2YXIgcmV0dXJuVmFsdWUgPSB0b0JpZ051bWJlcihudW1iZXIpLmRpdmlkZWRCeShnZXRWYWx1ZU9mVW5pdCh1bml0KSk7XG5cbiAgICByZXR1cm4gaXNCaWdOdW1iZXIobnVtYmVyKSA/IHJldHVyblZhbHVlIDogcmV0dXJuVmFsdWUudG9TdHJpbmcoMTApOyBcbn07XG5cbi8qKlxuICogVGFrZXMgYSBudW1iZXIgb2YgYSB1bml0IGFuZCBjb252ZXJ0cyBpdCB0byB3ZWkuXG4gKlxuICogUG9zc2libGUgdW5pdHMgYXJlOlxuICogICBTSSBTaG9ydCAgIFNJIEZ1bGwgICAgICAgIEVmZmlneSAgICAgICBPdGhlclxuICogLSBrd2VpICAgICAgIGZlbXRvZXRoZXIgICAgIGFkYVxuICogLSBtd2VpICAgICAgIHBpY29ldGhlciAgICAgIGJhYmJhZ2UgICAgICAgXG4gKiAtIGd3ZWkgICAgICAgbmFub2V0aGVyICAgICAgc2hhbm5vbiAgICAgIG5hbm9cbiAqIC0gLS0gICAgICAgICBtaWNyb2V0aGVyICAgICBzemFibyAgICAgICAgbWljcm9cbiAqIC0gLS0gICAgICAgICBtaWxsaWV0aGVyICAgICBmaW5uZXkgICAgICAgbWlsbGlcbiAqIC0gZXRoZXIgICAgICAtLSAgICAgICAgICAgICAtLVxuICogLSBrZXRoZXIgICAgICAgICAgICAgICAgICAgIGVpbnN0ZWluICAgICBncmFuZCBcbiAqIC0gbWV0aGVyXG4gKiAtIGdldGhlclxuICogLSB0ZXRoZXJcbiAqXG4gKiBAbWV0aG9kIHRvV2VpXG4gKiBAcGFyYW0ge051bWJlcnxTdHJpbmd8QmlnTnVtYmVyfSBudW1iZXIgY2FuIGJlIGEgbnVtYmVyLCBudW1iZXIgc3RyaW5nIG9yIGEgSEVYIG9mIGEgZGVjaW1hbFxuICogQHBhcmFtIHtTdHJpbmd9IHVuaXQgdGhlIHVuaXQgdG8gY29udmVydCBmcm9tLCBkZWZhdWx0IGV0aGVyXG4gKiBAcmV0dXJuIHtTdHJpbmd8T2JqZWN0fSBXaGVuIGdpdmVuIGEgQmlnTnVtYmVyIG9iamVjdCBpdCByZXR1cm5zIG9uZSBhcyB3ZWxsLCBvdGhlcndpc2UgYSBudW1iZXJcbiovXG52YXIgdG9XZWkgPSBmdW5jdGlvbihudW1iZXIsIHVuaXQpIHtcbiAgICB2YXIgcmV0dXJuVmFsdWUgPSB0b0JpZ051bWJlcihudW1iZXIpLnRpbWVzKGdldFZhbHVlT2ZVbml0KHVuaXQpKTtcblxuICAgIHJldHVybiBpc0JpZ051bWJlcihudW1iZXIpID8gcmV0dXJuVmFsdWUgOiByZXR1cm5WYWx1ZS50b1N0cmluZygxMCk7IFxufTtcblxuLyoqXG4gKiBUYWtlcyBhbiBpbnB1dCBhbmQgdHJhbnNmb3JtcyBpdCBpbnRvIGFuIGJpZ251bWJlclxuICpcbiAqIEBtZXRob2QgdG9CaWdOdW1iZXJcbiAqIEBwYXJhbSB7TnVtYmVyfFN0cmluZ3xCaWdOdW1iZXJ9IGEgbnVtYmVyLCBzdHJpbmcsIEhFWCBzdHJpbmcgb3IgQmlnTnVtYmVyXG4gKiBAcmV0dXJuIHtCaWdOdW1iZXJ9IEJpZ051bWJlclxuKi9cbnZhciB0b0JpZ051bWJlciA9IGZ1bmN0aW9uKG51bWJlcikge1xuICAgIC8qanNoaW50IG1heGNvbXBsZXhpdHk6NSAqL1xuICAgIG51bWJlciA9IG51bWJlciB8fCAwO1xuICAgIGlmIChpc0JpZ051bWJlcihudW1iZXIpKVxuICAgICAgICByZXR1cm4gbnVtYmVyO1xuXG4gICAgaWYgKGlzU3RyaW5nKG51bWJlcikgJiYgKG51bWJlci5pbmRleE9mKCcweCcpID09PSAwIHx8IG51bWJlci5pbmRleE9mKCctMHgnKSA9PT0gMCkpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBCaWdOdW1iZXIobnVtYmVyLnJlcGxhY2UoJzB4JywnJyksIDE2KTtcbiAgICB9XG4gICBcbiAgICByZXR1cm4gbmV3IEJpZ051bWJlcihudW1iZXIudG9TdHJpbmcoMTApLCAxMCk7XG59O1xuXG4vKipcbiAqIFRha2VzIGFuZCBpbnB1dCB0cmFuc2Zvcm1zIGl0IGludG8gYmlnbnVtYmVyIGFuZCBpZiBpdCBpcyBuZWdhdGl2ZSB2YWx1ZSwgaW50byB0d28ncyBjb21wbGVtZW50XG4gKlxuICogQG1ldGhvZCB0b1R3b3NDb21wbGVtZW50XG4gKiBAcGFyYW0ge051bWJlcnxTdHJpbmd8QmlnTnVtYmVyfVxuICogQHJldHVybiB7QmlnTnVtYmVyfVxuICovXG52YXIgdG9Ud29zQ29tcGxlbWVudCA9IGZ1bmN0aW9uIChudW1iZXIpIHtcbiAgICB2YXIgYmlnTnVtYmVyID0gdG9CaWdOdW1iZXIobnVtYmVyKTtcbiAgICBpZiAoYmlnTnVtYmVyLmxlc3NUaGFuKDApKSB7XG4gICAgICAgIHJldHVybiBuZXcgQmlnTnVtYmVyKFwiZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZlwiLCAxNikucGx1cyhiaWdOdW1iZXIpLnBsdXMoMSk7XG4gICAgfVxuICAgIHJldHVybiBiaWdOdW1iZXI7XG59O1xuXG4vKipcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gc3RyaW5nIGlzIHN0cmljdGx5IGFuIGFkZHJlc3NcbiAqXG4gKiBAbWV0aG9kIGlzU3RyaWN0QWRkcmVzc1xuICogQHBhcmFtIHtTdHJpbmd9IGFkZHJlc3MgdGhlIGdpdmVuIEhFWCBhZHJlc3NcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4qL1xudmFyIGlzU3RyaWN0QWRkcmVzcyA9IGZ1bmN0aW9uIChhZGRyZXNzKSB7XG4gICAgcmV0dXJuIC9eMHhbMC05YS1mXXs0MH0kLy50ZXN0KGFkZHJlc3MpO1xufTtcblxuLyoqXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIHN0cmluZyBpcyBhbiBhZGRyZXNzXG4gKlxuICogQG1ldGhvZCBpc0FkZHJlc3NcbiAqIEBwYXJhbSB7U3RyaW5nfSBhZGRyZXNzIHRoZSBnaXZlbiBIRVggYWRyZXNzXG4gKiBAcmV0dXJuIHtCb29sZWFufVxuKi9cbnZhciBpc0FkZHJlc3MgPSBmdW5jdGlvbiAoYWRkcmVzcykge1xuICAgIHJldHVybiAvXigweCk/WzAtOWEtZl17NDB9JC8udGVzdChhZGRyZXNzKTtcbn07XG5cbi8qKlxuICogVHJhbnNmb3JtcyBnaXZlbiBzdHJpbmcgdG8gdmFsaWQgMjAgYnl0ZXMtbGVuZ3RoIGFkZHJlcyB3aXRoIDB4IHByZWZpeFxuICpcbiAqIEBtZXRob2QgdG9BZGRyZXNzXG4gKiBAcGFyYW0ge1N0cmluZ30gYWRkcmVzc1xuICogQHJldHVybiB7U3RyaW5nfSBmb3JtYXR0ZWQgYWRkcmVzc1xuICovXG52YXIgdG9BZGRyZXNzID0gZnVuY3Rpb24gKGFkZHJlc3MpIHtcbiAgICBpZiAoaXNTdHJpY3RBZGRyZXNzKGFkZHJlc3MpKSB7XG4gICAgICAgIHJldHVybiBhZGRyZXNzO1xuICAgIH1cbiAgICBcbiAgICBpZiAoL15bMC05YS1mXXs0MH0kLy50ZXN0KGFkZHJlc3MpKSB7XG4gICAgICAgIHJldHVybiAnMHgnICsgYWRkcmVzcztcbiAgICB9XG5cbiAgICByZXR1cm4gJzB4JyArIHBhZExlZnQodG9IZXgoYWRkcmVzcykuc3Vic3RyKDIpLCA0MCk7XG59O1xuXG5cbi8qKlxuICogUmV0dXJucyB0cnVlIGlmIG9iamVjdCBpcyBCaWdOdW1iZXIsIG90aGVyd2lzZSBmYWxzZVxuICpcbiAqIEBtZXRob2QgaXNCaWdOdW1iZXJcbiAqIEBwYXJhbSB7T2JqZWN0fVxuICogQHJldHVybiB7Qm9vbGVhbn0gXG4gKi9cbnZhciBpc0JpZ051bWJlciA9IGZ1bmN0aW9uIChvYmplY3QpIHtcbiAgICByZXR1cm4gb2JqZWN0IGluc3RhbmNlb2YgQmlnTnVtYmVyIHx8XG4gICAgICAgIChvYmplY3QgJiYgb2JqZWN0LmNvbnN0cnVjdG9yICYmIG9iamVjdC5jb25zdHJ1Y3Rvci5uYW1lID09PSAnQmlnTnVtYmVyJyk7XG59O1xuXG4vKipcbiAqIFJldHVybnMgdHJ1ZSBpZiBvYmplY3QgaXMgc3RyaW5nLCBvdGhlcndpc2UgZmFsc2VcbiAqIFxuICogQG1ldGhvZCBpc1N0cmluZ1xuICogQHBhcmFtIHtPYmplY3R9XG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG52YXIgaXNTdHJpbmcgPSBmdW5jdGlvbiAob2JqZWN0KSB7XG4gICAgcmV0dXJuIHR5cGVvZiBvYmplY3QgPT09ICdzdHJpbmcnIHx8XG4gICAgICAgIChvYmplY3QgJiYgb2JqZWN0LmNvbnN0cnVjdG9yICYmIG9iamVjdC5jb25zdHJ1Y3Rvci5uYW1lID09PSAnU3RyaW5nJyk7XG59O1xuXG4vKipcbiAqIFJldHVybnMgdHJ1ZSBpZiBvYmplY3QgaXMgZnVuY3Rpb24sIG90aGVyd2lzZSBmYWxzZVxuICpcbiAqIEBtZXRob2QgaXNGdW5jdGlvblxuICogQHBhcmFtIHtPYmplY3R9XG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG52YXIgaXNGdW5jdGlvbiA9IGZ1bmN0aW9uIChvYmplY3QpIHtcbiAgICByZXR1cm4gdHlwZW9mIG9iamVjdCA9PT0gJ2Z1bmN0aW9uJztcbn07XG5cbi8qKlxuICogUmV0dXJucyB0cnVlIGlmIG9iamVjdCBpcyBPYmpldCwgb3RoZXJ3aXNlIGZhbHNlXG4gKlxuICogQG1ldGhvZCBpc09iamVjdFxuICogQHBhcmFtIHtPYmplY3R9XG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG52YXIgaXNPYmplY3QgPSBmdW5jdGlvbiAob2JqZWN0KSB7XG4gICAgcmV0dXJuIHR5cGVvZiBvYmplY3QgPT09ICdvYmplY3QnO1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIHRydWUgaWYgb2JqZWN0IGlzIGJvb2xlYW4sIG90aGVyd2lzZSBmYWxzZVxuICpcbiAqIEBtZXRob2QgaXNCb29sZWFuXG4gKiBAcGFyYW0ge09iamVjdH1cbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbnZhciBpc0Jvb2xlYW4gPSBmdW5jdGlvbiAob2JqZWN0KSB7XG4gICAgcmV0dXJuIHR5cGVvZiBvYmplY3QgPT09ICdib29sZWFuJztcbn07XG5cbi8qKlxuICogUmV0dXJucyB0cnVlIGlmIG9iamVjdCBpcyBhcnJheSwgb3RoZXJ3aXNlIGZhbHNlXG4gKlxuICogQG1ldGhvZCBpc0FycmF5XG4gKiBAcGFyYW0ge09iamVjdH1cbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbnZhciBpc0FycmF5ID0gZnVuY3Rpb24gKG9iamVjdCkge1xuICAgIHJldHVybiBvYmplY3QgaW5zdGFuY2VvZiBBcnJheTsgXG59O1xuXG4vKipcbiAqIFJldHVybnMgdHJ1ZSBpZiBnaXZlbiBzdHJpbmcgaXMgdmFsaWQganNvbiBvYmplY3RcbiAqIFxuICogQG1ldGhvZCBpc0pzb25cbiAqIEBwYXJhbSB7U3RyaW5nfVxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqL1xudmFyIGlzSnNvbiA9IGZ1bmN0aW9uIChzdHIpIHtcbiAgICB0cnkge1xuICAgICAgICByZXR1cm4gISFKU09OLnBhcnNlKHN0cik7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgY2FsbGVkIHRvIGNoZWNrIGlmIHN0cmluZyBpcyB2YWxpZCBldGhlcmV1bSBJQkFOIG51bWJlclxuICogU3VwcG9ydHMgZGlyZWN0IGFuZCBpbmRpcmVjdCBJQkFOc1xuICpcbiAqIEBtZXRob2QgaXNJQkFOXG4gKiBAcGFyYW0ge1N0cmluZ31cbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbnZhciBpc0lCQU4gPSBmdW5jdGlvbiAoaWJhbikge1xuICAgIHJldHVybiAvXlhFWzAtOV17Mn0oRVRIWzAtOUEtWl17MTN9fFswLTlBLVpdezMwfSkkLy50ZXN0KGliYW4pO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgcGFkTGVmdDogcGFkTGVmdCxcbiAgICB0b0hleDogdG9IZXgsXG4gICAgdG9EZWNpbWFsOiB0b0RlY2ltYWwsXG4gICAgZnJvbURlY2ltYWw6IGZyb21EZWNpbWFsLFxuICAgIHRvQXNjaWk6IHRvQXNjaWksXG4gICAgZnJvbUFzY2lpOiBmcm9tQXNjaWksXG4gICAgdHJhbnNmb3JtVG9GdWxsTmFtZTogdHJhbnNmb3JtVG9GdWxsTmFtZSxcbiAgICBleHRyYWN0RGlzcGxheU5hbWU6IGV4dHJhY3REaXNwbGF5TmFtZSxcbiAgICBleHRyYWN0VHlwZU5hbWU6IGV4dHJhY3RUeXBlTmFtZSxcbiAgICB0b1dlaTogdG9XZWksXG4gICAgZnJvbVdlaTogZnJvbVdlaSxcbiAgICB0b0JpZ051bWJlcjogdG9CaWdOdW1iZXIsXG4gICAgdG9Ud29zQ29tcGxlbWVudDogdG9Ud29zQ29tcGxlbWVudCxcbiAgICB0b0FkZHJlc3M6IHRvQWRkcmVzcyxcbiAgICBpc0JpZ051bWJlcjogaXNCaWdOdW1iZXIsXG4gICAgaXNTdHJpY3RBZGRyZXNzOiBpc1N0cmljdEFkZHJlc3MsXG4gICAgaXNBZGRyZXNzOiBpc0FkZHJlc3MsXG4gICAgaXNGdW5jdGlvbjogaXNGdW5jdGlvbixcbiAgICBpc1N0cmluZzogaXNTdHJpbmcsXG4gICAgaXNPYmplY3Q6IGlzT2JqZWN0LFxuICAgIGlzQm9vbGVhbjogaXNCb29sZWFuLFxuICAgIGlzQXJyYXk6IGlzQXJyYXksXG4gICAgaXNKc29uOiBpc0pzb24sXG4gICAgaXNJQkFOOiBpc0lCQU5cbn07XG5cbiIsIm1vZHVsZS5leHBvcnRzPXtcbiAgICBcInZlcnNpb25cIjogXCIwLjUuMFwiXG59XG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBAZmlsZSB3ZWIzLmpzXG4gKiBAYXV0aG9yczpcbiAqICAgSmVmZnJleSBXaWxja2UgPGplZmZAZXRoZGV2LmNvbT5cbiAqICAgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiAgIE1hcmlhbiBPYW5jZWEgPG1hcmlhbkBldGhkZXYuY29tPlxuICogICBGYWJpYW4gVm9nZWxzdGVsbGVyIDxmYWJpYW5AZXRoZGV2LmNvbT5cbiAqICAgR2F2IFdvb2QgPGdAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTRcbiAqL1xuXG52YXIgdmVyc2lvbiA9IHJlcXVpcmUoJy4vdmVyc2lvbi5qc29uJyk7XG52YXIgbmV0ID0gcmVxdWlyZSgnLi93ZWIzL25ldCcpO1xudmFyIGV0aCA9IHJlcXVpcmUoJy4vd2ViMy9ldGgnKTtcbnZhciBkYiA9IHJlcXVpcmUoJy4vd2ViMy9kYicpO1xudmFyIHNoaCA9IHJlcXVpcmUoJy4vd2ViMy9zaGgnKTtcbnZhciB3YXRjaGVzID0gcmVxdWlyZSgnLi93ZWIzL3dhdGNoZXMnKTtcbnZhciBGaWx0ZXIgPSByZXF1aXJlKCcuL3dlYjMvZmlsdGVyJyk7XG52YXIgdXRpbHMgPSByZXF1aXJlKCcuL3V0aWxzL3V0aWxzJyk7XG52YXIgZm9ybWF0dGVycyA9IHJlcXVpcmUoJy4vd2ViMy9mb3JtYXR0ZXJzJyk7XG52YXIgUmVxdWVzdE1hbmFnZXIgPSByZXF1aXJlKCcuL3dlYjMvcmVxdWVzdG1hbmFnZXInKTtcbnZhciBjID0gcmVxdWlyZSgnLi91dGlscy9jb25maWcnKTtcbnZhciBQcm9wZXJ0eSA9IHJlcXVpcmUoJy4vd2ViMy9wcm9wZXJ0eScpO1xudmFyIEJhdGNoID0gcmVxdWlyZSgnLi93ZWIzL2JhdGNoJyk7XG52YXIgc2hhMyA9IHJlcXVpcmUoJy4vdXRpbHMvc2hhMycpO1xuXG52YXIgd2ViM1Byb3BlcnRpZXMgPSBbXG4gICAgbmV3IFByb3BlcnR5KHtcbiAgICAgICAgbmFtZTogJ3ZlcnNpb24uY2xpZW50JyxcbiAgICAgICAgZ2V0dGVyOiAnd2ViM19jbGllbnRWZXJzaW9uJ1xuICAgIH0pLFxuICAgIG5ldyBQcm9wZXJ0eSh7XG4gICAgICAgIG5hbWU6ICd2ZXJzaW9uLm5ldHdvcmsnLFxuICAgICAgICBnZXR0ZXI6ICduZXRfdmVyc2lvbicsXG4gICAgICAgIGlucHV0Rm9ybWF0dGVyOiB1dGlscy50b0RlY2ltYWxcbiAgICB9KSxcbiAgICBuZXcgUHJvcGVydHkoe1xuICAgICAgICBuYW1lOiAndmVyc2lvbi5ldGhlcmV1bScsXG4gICAgICAgIGdldHRlcjogJ2V0aF9wcm90b2NvbFZlcnNpb24nLFxuICAgICAgICBpbnB1dEZvcm1hdHRlcjogdXRpbHMudG9EZWNpbWFsXG4gICAgfSksXG4gICAgbmV3IFByb3BlcnR5KHtcbiAgICAgICAgbmFtZTogJ3ZlcnNpb24ud2hpc3BlcicsXG4gICAgICAgIGdldHRlcjogJ3NoaF92ZXJzaW9uJyxcbiAgICAgICAgaW5wdXRGb3JtYXR0ZXI6IHV0aWxzLnRvRGVjaW1hbFxuICAgIH0pXG5dO1xuXG4vLy8gY3JlYXRlcyBtZXRob2RzIGluIGEgZ2l2ZW4gb2JqZWN0IGJhc2VkIG9uIG1ldGhvZCBkZXNjcmlwdGlvbiBvbiBpbnB1dFxuLy8vIHNldHVwcyBhcGkgY2FsbHMgZm9yIHRoZXNlIG1ldGhvZHNcbnZhciBzZXR1cE1ldGhvZHMgPSBmdW5jdGlvbiAob2JqLCBtZXRob2RzKSB7XG4gICAgbWV0aG9kcy5mb3JFYWNoKGZ1bmN0aW9uIChtZXRob2QpIHtcbiAgICAgICAgbWV0aG9kLmF0dGFjaFRvT2JqZWN0KG9iaik7XG4gICAgfSk7XG59O1xuXG4vLy8gY3JlYXRlcyBwcm9wZXJ0aWVzIGluIGEgZ2l2ZW4gb2JqZWN0IGJhc2VkIG9uIHByb3BlcnRpZXMgZGVzY3JpcHRpb24gb24gaW5wdXRcbi8vLyBzZXR1cHMgYXBpIGNhbGxzIGZvciB0aGVzZSBwcm9wZXJ0aWVzXG52YXIgc2V0dXBQcm9wZXJ0aWVzID0gZnVuY3Rpb24gKG9iaiwgcHJvcGVydGllcykge1xuICAgIHByb3BlcnRpZXMuZm9yRWFjaChmdW5jdGlvbiAocHJvcGVydHkpIHtcbiAgICAgICAgcHJvcGVydHkuYXR0YWNoVG9PYmplY3Qob2JqKTtcbiAgICB9KTtcbn07XG5cbi8vLyBzZXR1cHMgd2ViMyBvYmplY3QsIGFuZCBpdCdzIGluLWJyb3dzZXIgZXhlY3V0ZWQgbWV0aG9kc1xudmFyIHdlYjMgPSB7fTtcbndlYjMucHJvdmlkZXJzID0ge307XG53ZWIzLnZlcnNpb24gPSB7fTtcbndlYjMudmVyc2lvbi5hcGkgPSB2ZXJzaW9uLnZlcnNpb247XG53ZWIzLmV0aCA9IHt9O1xuXG4vKmpzaGludCBtYXhwYXJhbXM6NCAqL1xud2ViMy5ldGguZmlsdGVyID0gZnVuY3Rpb24gKGZpbCwgZXZlbnRQYXJhbXMsIG9wdGlvbnMsIGZvcm1hdHRlcikge1xuXG4gICAgLy8gaWYgaXRzIGV2ZW50LCB0cmVhdCBpdCBkaWZmZXJlbnRseVxuICAgIC8vIFRPRE86IHNpbXBsaWZ5IGFuZCByZW1vdmVcbiAgICBpZiAoZmlsLl9pc0V2ZW50KSB7XG4gICAgICAgIHJldHVybiBmaWwoZXZlbnRQYXJhbXMsIG9wdGlvbnMpO1xuICAgIH1cblxuICAgIC8vIHdoYXQgb3V0cHV0TG9nRm9ybWF0dGVyPyB0aGF0J3Mgd3JvbmdcbiAgICAvL3JldHVybiBuZXcgRmlsdGVyKGZpbCwgd2F0Y2hlcy5ldGgoKSwgZm9ybWF0dGVycy5vdXRwdXRMb2dGb3JtYXR0ZXIpO1xuICAgIHJldHVybiBuZXcgRmlsdGVyKGZpbCwgd2F0Y2hlcy5ldGgoKSwgZm9ybWF0dGVyIHx8IGZvcm1hdHRlcnMub3V0cHV0TG9nRm9ybWF0dGVyKTtcbn07XG4vKmpzaGludCBtYXhwYXJhbXM6MyAqL1xuXG53ZWIzLnNoaCA9IHt9O1xud2ViMy5zaGguZmlsdGVyID0gZnVuY3Rpb24gKGZpbCkge1xuICAgIHJldHVybiBuZXcgRmlsdGVyKGZpbCwgd2F0Y2hlcy5zaGgoKSwgZm9ybWF0dGVycy5vdXRwdXRQb3N0Rm9ybWF0dGVyKTtcbn07XG53ZWIzLm5ldCA9IHt9O1xud2ViMy5kYiA9IHt9O1xud2ViMy5zZXRQcm92aWRlciA9IGZ1bmN0aW9uIChwcm92aWRlcikge1xuICAgIFJlcXVlc3RNYW5hZ2VyLmdldEluc3RhbmNlKCkuc2V0UHJvdmlkZXIocHJvdmlkZXIpO1xufTtcbndlYjMucmVzZXQgPSBmdW5jdGlvbiAoKSB7XG4gICAgUmVxdWVzdE1hbmFnZXIuZ2V0SW5zdGFuY2UoKS5yZXNldCgpO1xuICAgIGMuZGVmYXVsdEJsb2NrID0gJ2xhdGVzdCc7XG4gICAgYy5kZWZhdWx0QWNjb3VudCA9IHVuZGVmaW5lZDtcbn07XG53ZWIzLnRvSGV4ID0gdXRpbHMudG9IZXg7XG53ZWIzLnRvQXNjaWkgPSB1dGlscy50b0FzY2lpO1xud2ViMy5mcm9tQXNjaWkgPSB1dGlscy5mcm9tQXNjaWk7XG53ZWIzLnRvRGVjaW1hbCA9IHV0aWxzLnRvRGVjaW1hbDtcbndlYjMuZnJvbURlY2ltYWwgPSB1dGlscy5mcm9tRGVjaW1hbDtcbndlYjMudG9CaWdOdW1iZXIgPSB1dGlscy50b0JpZ051bWJlcjtcbndlYjMudG9XZWkgPSB1dGlscy50b1dlaTtcbndlYjMuZnJvbVdlaSA9IHV0aWxzLmZyb21XZWk7XG53ZWIzLmlzQWRkcmVzcyA9IHV0aWxzLmlzQWRkcmVzcztcbndlYjMuaXNJQkFOID0gdXRpbHMuaXNJQkFOO1xud2ViMy5zaGEzID0gc2hhMztcbndlYjMuY3JlYXRlQmF0Y2ggPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIG5ldyBCYXRjaCgpO1xufTtcblxuLy8gQUREIGRlZmF1bHRibG9ja1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KHdlYjMuZXRoLCAnZGVmYXVsdEJsb2NrJywge1xuICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gYy5kZWZhdWx0QmxvY2s7XG4gICAgfSxcbiAgICBzZXQ6IGZ1bmN0aW9uICh2YWwpIHtcbiAgICAgICAgYy5kZWZhdWx0QmxvY2sgPSB2YWw7XG4gICAgICAgIHJldHVybiB2YWw7XG4gICAgfVxufSk7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eSh3ZWIzLmV0aCwgJ2RlZmF1bHRBY2NvdW50Jywge1xuICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gYy5kZWZhdWx0QWNjb3VudDtcbiAgICB9LFxuICAgIHNldDogZnVuY3Rpb24gKHZhbCkge1xuICAgICAgICBjLmRlZmF1bHRBY2NvdW50ID0gdmFsO1xuICAgICAgICByZXR1cm4gdmFsO1xuICAgIH1cbn0pO1xuXG4vLy8gc2V0dXBzIGFsbCBhcGkgbWV0aG9kc1xuc2V0dXBQcm9wZXJ0aWVzKHdlYjMsIHdlYjNQcm9wZXJ0aWVzKTtcbnNldHVwTWV0aG9kcyh3ZWIzLm5ldCwgbmV0Lm1ldGhvZHMpO1xuc2V0dXBQcm9wZXJ0aWVzKHdlYjMubmV0LCBuZXQucHJvcGVydGllcyk7XG5zZXR1cE1ldGhvZHMod2ViMy5ldGgsIGV0aC5tZXRob2RzKTtcbnNldHVwUHJvcGVydGllcyh3ZWIzLmV0aCwgZXRoLnByb3BlcnRpZXMpO1xuc2V0dXBNZXRob2RzKHdlYjMuZGIsIGRiLm1ldGhvZHMpO1xuc2V0dXBNZXRob2RzKHdlYjMuc2hoLCBzaGgubWV0aG9kcyk7XG5cbm1vZHVsZS5leHBvcnRzID0gd2ViMztcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogXG4gKiBAZmlsZSBiYXRjaC5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgUmVxdWVzdE1hbmFnZXIgPSByZXF1aXJlKCcuL3JlcXVlc3RtYW5hZ2VyJyk7XG5cbnZhciBCYXRjaCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnJlcXVlc3RzID0gW107XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gYWRkIGNyZWF0ZSBuZXcgcmVxdWVzdCB0byBiYXRjaCByZXF1ZXN0XG4gKlxuICogQG1ldGhvZCBhZGRcbiAqIEBwYXJhbSB7T2JqZWN0fSBqc29ucnBjIHJlcXVldCBvYmplY3RcbiAqL1xuQmF0Y2gucHJvdG90eXBlLmFkZCA9IGZ1bmN0aW9uIChyZXF1ZXN0KSB7XG4gICAgdGhpcy5yZXF1ZXN0cy5wdXNoKHJlcXVlc3QpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGV4ZWN1dGUgYmF0Y2ggcmVxdWVzdFxuICpcbiAqIEBtZXRob2QgZXhlY3V0ZVxuICovXG5CYXRjaC5wcm90b3R5cGUuZXhlY3V0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgcmVxdWVzdHMgPSB0aGlzLnJlcXVlc3RzO1xuICAgIFJlcXVlc3RNYW5hZ2VyLmdldEluc3RhbmNlKCkuc2VuZEJhdGNoKHJlcXVlc3RzLCBmdW5jdGlvbiAoZXJyLCByZXN1bHRzKSB7XG4gICAgICAgIHJlc3VsdHMgPSByZXN1bHRzIHx8IFtdO1xuICAgICAgICByZXF1ZXN0cy5tYXAoZnVuY3Rpb24gKHJlcXVlc3QsIGluZGV4KSB7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0c1tpbmRleF0gfHwge307XG4gICAgICAgIH0pLm1hcChmdW5jdGlvbiAocmVzdWx0LCBpbmRleCkge1xuICAgICAgICAgICAgcmV0dXJuIHJlcXVlc3RzW2luZGV4XS5mb3JtYXQgPyByZXF1ZXN0c1tpbmRleF0uZm9ybWF0KHJlc3VsdC5yZXN1bHQpIDogcmVzdWx0LnJlc3VsdDtcbiAgICAgICAgfSkuZm9yRWFjaChmdW5jdGlvbiAocmVzdWx0LCBpbmRleCkge1xuICAgICAgICAgICAgaWYgKHJlcXVlc3RzW2luZGV4XS5jYWxsYmFjaykge1xuICAgICAgICAgICAgICAgIHJlcXVlc3RzW2luZGV4XS5jYWxsYmFjayhlcnIsIHJlc3VsdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH0pOyBcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gQmF0Y2g7XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqIFxuICogQGZpbGUgY29udHJhY3QuanNcbiAqIEBhdXRob3IgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE0XG4gKi9cblxudmFyIHdlYjMgPSByZXF1aXJlKCcuLi93ZWIzJyk7IFxudmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMvdXRpbHMnKTtcbnZhciBjb2RlciA9IHJlcXVpcmUoJy4uL3NvbGlkaXR5L2NvZGVyJyk7XG52YXIgU29saWRpdHlFdmVudCA9IHJlcXVpcmUoJy4vZXZlbnQnKTtcbnZhciBTb2xpZGl0eUZ1bmN0aW9uID0gcmVxdWlyZSgnLi9mdW5jdGlvbicpO1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZW5jb2RlIGNvbnN0cnVjdG9yIHBhcmFtc1xuICpcbiAqIEBtZXRob2QgZW5jb2RlQ29uc3RydWN0b3JQYXJhbXNcbiAqIEBwYXJhbSB7QXJyYXl9IGFiaVxuICogQHBhcmFtIHtBcnJheX0gY29uc3RydWN0b3IgcGFyYW1zXG4gKi9cbnZhciBlbmNvZGVDb25zdHJ1Y3RvclBhcmFtcyA9IGZ1bmN0aW9uIChhYmksIHBhcmFtcykge1xuICAgIHJldHVybiBhYmkuZmlsdGVyKGZ1bmN0aW9uIChqc29uKSB7XG4gICAgICAgIHJldHVybiBqc29uLnR5cGUgPT09ICdjb25zdHJ1Y3RvcicgJiYganNvbi5pbnB1dHMubGVuZ3RoID09PSBwYXJhbXMubGVuZ3RoO1xuICAgIH0pLm1hcChmdW5jdGlvbiAoanNvbikge1xuICAgICAgICByZXR1cm4ganNvbi5pbnB1dHMubWFwKGZ1bmN0aW9uIChpbnB1dCkge1xuICAgICAgICAgICAgcmV0dXJuIGlucHV0LnR5cGU7XG4gICAgICAgIH0pO1xuICAgIH0pLm1hcChmdW5jdGlvbiAodHlwZXMpIHtcbiAgICAgICAgcmV0dXJuIGNvZGVyLmVuY29kZVBhcmFtcyh0eXBlcywgcGFyYW1zKTtcbiAgICB9KVswXSB8fCAnJztcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBhZGQgZnVuY3Rpb25zIHRvIGNvbnRyYWN0IG9iamVjdFxuICpcbiAqIEBtZXRob2QgYWRkRnVuY3Rpb25zVG9Db250cmFjdFxuICogQHBhcmFtIHtDb250cmFjdH0gY29udHJhY3RcbiAqIEBwYXJhbSB7QXJyYXl9IGFiaVxuICovXG52YXIgYWRkRnVuY3Rpb25zVG9Db250cmFjdCA9IGZ1bmN0aW9uIChjb250cmFjdCwgYWJpKSB7XG4gICAgYWJpLmZpbHRlcihmdW5jdGlvbiAoanNvbikge1xuICAgICAgICByZXR1cm4ganNvbi50eXBlID09PSAnZnVuY3Rpb24nO1xuICAgIH0pLm1hcChmdW5jdGlvbiAoanNvbikge1xuICAgICAgICByZXR1cm4gbmV3IFNvbGlkaXR5RnVuY3Rpb24oanNvbiwgY29udHJhY3QuYWRkcmVzcyk7XG4gICAgfSkuZm9yRWFjaChmdW5jdGlvbiAoZikge1xuICAgICAgICBmLmF0dGFjaFRvQ29udHJhY3QoY29udHJhY3QpO1xuICAgIH0pO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGFkZCBldmVudHMgdG8gY29udHJhY3Qgb2JqZWN0XG4gKlxuICogQG1ldGhvZCBhZGRFdmVudHNUb0NvbnRyYWN0XG4gKiBAcGFyYW0ge0NvbnRyYWN0fSBjb250cmFjdFxuICogQHBhcmFtIHtBcnJheX0gYWJpXG4gKi9cbnZhciBhZGRFdmVudHNUb0NvbnRyYWN0ID0gZnVuY3Rpb24gKGNvbnRyYWN0LCBhYmkpIHtcbiAgICBhYmkuZmlsdGVyKGZ1bmN0aW9uIChqc29uKSB7XG4gICAgICAgIHJldHVybiBqc29uLnR5cGUgPT09ICdldmVudCc7XG4gICAgfSkubWFwKGZ1bmN0aW9uIChqc29uKSB7XG4gICAgICAgIHJldHVybiBuZXcgU29saWRpdHlFdmVudChqc29uLCBjb250cmFjdC5hZGRyZXNzKTtcbiAgICB9KS5mb3JFYWNoKGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUuYXR0YWNoVG9Db250cmFjdChjb250cmFjdCk7XG4gICAgfSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gY3JlYXRlIG5ldyBDb250cmFjdEZhY3RvcnlcbiAqXG4gKiBAbWV0aG9kIGNvbnRyYWN0XG4gKiBAcGFyYW0ge0FycmF5fSBhYmlcbiAqIEByZXR1cm5zIHtDb250cmFjdEZhY3Rvcnl9IG5ldyBjb250cmFjdCBmYWN0b3J5XG4gKi9cbnZhciBjb250cmFjdCA9IGZ1bmN0aW9uIChhYmkpIHtcbiAgICByZXR1cm4gbmV3IENvbnRyYWN0RmFjdG9yeShhYmkpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGNyZWF0ZSBuZXcgQ29udHJhY3RGYWN0b3J5IGluc3RhbmNlXG4gKlxuICogQG1ldGhvZCBDb250cmFjdEZhY3RvcnlcbiAqIEBwYXJhbSB7QXJyYXl9IGFiaVxuICovXG52YXIgQ29udHJhY3RGYWN0b3J5ID0gZnVuY3Rpb24gKGFiaSkge1xuICAgIHRoaXMuYWJpID0gYWJpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGNyZWF0ZSBuZXcgY29udHJhY3Qgb24gYSBibG9ja2NoYWluXG4gKiBcbiAqIEBtZXRob2QgbmV3XG4gKiBAcGFyYW0ge0FueX0gY29udHJhY3QgY29uc3RydWN0b3IgcGFyYW0xIChvcHRpb25hbClcbiAqIEBwYXJhbSB7QW55fSBjb250cmFjdCBjb25zdHJ1Y3RvciBwYXJhbTIgKG9wdGlvbmFsKVxuICogQHBhcmFtIHtPYmplY3R9IGNvbnRyYWN0IHRyYW5zYWN0aW9uIG9iamVjdCAocmVxdWlyZWQpXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFja1xuICogQHJldHVybnMge0NvbnRyYWN0fSByZXR1cm5zIGNvbnRyYWN0IGlmIG5vIGNhbGxiYWNrIHdhcyBwYXNzZWQsXG4gKiBvdGhlcndpc2UgY2FsbHMgY2FsbGJhY2sgZnVuY3Rpb24gKGVyciwgY29udHJhY3QpXG4gKi9cbkNvbnRyYWN0RmFjdG9yeS5wcm90b3R5cGUubmV3ID0gZnVuY3Rpb24gKCkge1xuICAgIC8vIHBhcnNlIGFyZ3VtZW50c1xuICAgIHZhciBvcHRpb25zID0ge307IC8vIHJlcXVpcmVkIVxuICAgIHZhciBjYWxsYmFjaztcblxuICAgIHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKTtcbiAgICBpZiAodXRpbHMuaXNGdW5jdGlvbihhcmdzW2FyZ3MubGVuZ3RoIC0gMV0pKSB7XG4gICAgICAgIGNhbGxiYWNrID0gYXJncy5wb3AoKTtcbiAgICB9XG5cbiAgICB2YXIgbGFzdCA9IGFyZ3NbYXJncy5sZW5ndGggLSAxXTtcbiAgICBpZiAodXRpbHMuaXNPYmplY3QobGFzdCkgJiYgIXV0aWxzLmlzQXJyYXkobGFzdCkpIHtcbiAgICAgICAgb3B0aW9ucyA9IGFyZ3MucG9wKCk7XG4gICAgfVxuXG4gICAgLy8gdGhyb3cgYW4gZXJyb3IgaWYgdGhlcmUgYXJlIG5vIG9wdGlvbnNcblxuICAgIHZhciBieXRlcyA9IGVuY29kZUNvbnN0cnVjdG9yUGFyYW1zKHRoaXMuYWJpLCBhcmdzKTtcbiAgICBvcHRpb25zLmRhdGEgKz0gYnl0ZXM7XG5cbiAgICBpZiAoIWNhbGxiYWNrKSB7XG4gICAgICAgIHZhciBhZGRyZXNzID0gd2ViMy5ldGguc2VuZFRyYW5zYWN0aW9uKG9wdGlvbnMpO1xuICAgICAgICByZXR1cm4gdGhpcy5hdChhZGRyZXNzKTtcbiAgICB9XG4gIFxuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB3ZWIzLmV0aC5zZW5kVHJhbnNhY3Rpb24ob3B0aW9ucywgZnVuY3Rpb24gKGVyciwgYWRkcmVzcykge1xuICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICBjYWxsYmFjayhlcnIpO1xuICAgICAgICB9XG4gICAgICAgIHNlbGYuYXQoYWRkcmVzcywgY2FsbGJhY2spOyBcbiAgICB9KTsgXG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZ2V0IGFjY2VzcyB0byBleGlzdGluZyBjb250cmFjdCBvbiBhIGJsb2NrY2hhaW5cbiAqXG4gKiBAbWV0aG9kIGF0XG4gKiBAcGFyYW0ge0FkZHJlc3N9IGNvbnRyYWN0IGFkZHJlc3MgKHJlcXVpcmVkKVxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sge29wdGlvbmFsKVxuICogQHJldHVybnMge0NvbnRyYWN0fSByZXR1cm5zIGNvbnRyYWN0IGlmIG5vIGNhbGxiYWNrIHdhcyBwYXNzZWQsXG4gKiBvdGhlcndpc2UgY2FsbHMgY2FsbGJhY2sgZnVuY3Rpb24gKGVyciwgY29udHJhY3QpXG4gKi9cbkNvbnRyYWN0RmFjdG9yeS5wcm90b3R5cGUuYXQgPSBmdW5jdGlvbiAoYWRkcmVzcywgY2FsbGJhY2spIHtcbiAgICAvLyBUT0RPOiBhZGRyZXNzIGlzIHJlcXVpcmVkXG4gICAgXG4gICAgaWYgKGNhbGxiYWNrKSB7XG4gICAgICAgIGNhbGxiYWNrKG51bGwsIG5ldyBDb250cmFjdCh0aGlzLmFiaSwgYWRkcmVzcykpO1xuICAgIH0gXG4gICAgcmV0dXJuIG5ldyBDb250cmFjdCh0aGlzLmFiaSwgYWRkcmVzcyk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gY3JlYXRlIG5ldyBjb250cmFjdCBpbnN0YW5jZVxuICpcbiAqIEBtZXRob2QgQ29udHJhY3RcbiAqIEBwYXJhbSB7QXJyYXl9IGFiaVxuICogQHBhcmFtIHtBZGRyZXNzfSBjb250cmFjdCBhZGRyZXNzXG4gKi9cbnZhciBDb250cmFjdCA9IGZ1bmN0aW9uIChhYmksIGFkZHJlc3MpIHtcbiAgICB0aGlzLmFkZHJlc3MgPSBhZGRyZXNzO1xuICAgIGFkZEZ1bmN0aW9uc1RvQ29udHJhY3QodGhpcywgYWJpKTtcbiAgICBhZGRFdmVudHNUb0NvbnRyYWN0KHRoaXMsIGFiaSk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNvbnRyYWN0O1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBAZmlsZSBkYi5qc1xuICogQGF1dGhvcnM6XG4gKiAgIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbnZhciBNZXRob2QgPSByZXF1aXJlKCcuL21ldGhvZCcpO1xuXG52YXIgcHV0U3RyaW5nID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ3B1dFN0cmluZycsXG4gICAgY2FsbDogJ2RiX3B1dFN0cmluZycsXG4gICAgcGFyYW1zOiAzXG59KTtcblxuXG52YXIgZ2V0U3RyaW5nID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2dldFN0cmluZycsXG4gICAgY2FsbDogJ2RiX2dldFN0cmluZycsXG4gICAgcGFyYW1zOiAyXG59KTtcblxudmFyIHB1dEhleCA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdwdXRIZXgnLFxuICAgIGNhbGw6ICdkYl9wdXRIZXgnLFxuICAgIHBhcmFtczogM1xufSk7XG5cbnZhciBnZXRIZXggPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnZ2V0SGV4JyxcbiAgICBjYWxsOiAnZGJfZ2V0SGV4JyxcbiAgICBwYXJhbXM6IDJcbn0pO1xuXG52YXIgbWV0aG9kcyA9IFtcbiAgICBwdXRTdHJpbmcsIGdldFN0cmluZywgcHV0SGV4LCBnZXRIZXhcbl07XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIG1ldGhvZHM6IG1ldGhvZHNcbn07XG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBcbiAqIEBmaWxlIGVycm9ycy5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBJbnZhbGlkTnVtYmVyT2ZQYXJhbXM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBFcnJvcignSW52YWxpZCBudW1iZXIgb2YgaW5wdXQgcGFyYW1ldGVycycpO1xuICAgIH0sXG4gICAgSW52YWxpZENvbm5lY3Rpb246IGZ1bmN0aW9uIChob3N0KXtcbiAgICAgICAgcmV0dXJuIG5ldyBFcnJvcignQ09OTkVDVElPTiBFUlJPUjogQ291bGRuXFwndCBjb25uZWN0IHRvIG5vZGUgJysgaG9zdCArJywgaXMgaXQgcnVubmluZz8nKTtcbiAgICB9LFxuICAgIEludmFsaWRQcm92aWRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gbmV3IEVycm9yKCdQcm92aWRvciBub3Qgc2V0IG9yIGludmFsaWQnKTtcbiAgICB9LFxuICAgIEludmFsaWRSZXNwb25zZTogZnVuY3Rpb24gKHJlc3VsdCl7XG4gICAgICAgIHZhciBtZXNzYWdlID0gISFyZXN1bHQgJiYgISFyZXN1bHQuZXJyb3IgJiYgISFyZXN1bHQuZXJyb3IubWVzc2FnZSA/IHJlc3VsdC5lcnJvci5tZXNzYWdlIDogJ0ludmFsaWQgSlNPTiBSUEMgcmVzcG9uc2UnO1xuICAgICAgICByZXR1cm4gbmV3IEVycm9yKG1lc3NhZ2UpO1xuICAgIH1cbn07XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqXG4gKiBAZmlsZSBldGguanNcbiAqIEBhdXRob3IgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiBAYXV0aG9yIEZhYmlhbiBWb2dlbHN0ZWxsZXIgPGZhYmlhbkBldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbi8qKlxuICogV2ViM1xuICpcbiAqIEBtb2R1bGUgd2ViM1xuICovXG5cbi8qKlxuICogRXRoIG1ldGhvZHMgYW5kIHByb3BlcnRpZXNcbiAqXG4gKiBBbiBleGFtcGxlIG1ldGhvZCBvYmplY3QgY2FuIGxvb2sgYXMgZm9sbG93czpcbiAqXG4gKiAgICAgIHtcbiAqICAgICAgbmFtZTogJ2dldEJsb2NrJyxcbiAqICAgICAgY2FsbDogYmxvY2tDYWxsLFxuICogICAgICBwYXJhbXM6IDIsXG4gKiAgICAgIG91dHB1dEZvcm1hdHRlcjogZm9ybWF0dGVycy5vdXRwdXRCbG9ja0Zvcm1hdHRlcixcbiAqICAgICAgaW5wdXRGb3JtYXR0ZXI6IFsgLy8gY2FuIGJlIGEgZm9ybWF0dGVyIGZ1bmNpdG9uIG9yIGFuIGFycmF5IG9mIGZ1bmN0aW9ucy4gV2hlcmUgZWFjaCBpdGVtIGluIHRoZSBhcnJheSB3aWxsIGJlIHVzZWQgZm9yIG9uZSBwYXJhbWV0ZXJcbiAqICAgICAgICAgICB1dGlscy50b0hleCwgLy8gZm9ybWF0cyBwYXJhbXRlciAxXG4gKiAgICAgICAgICAgZnVuY3Rpb24ocGFyYW0peyByZXR1cm4gISFwYXJhbTsgfSAvLyBmb3JtYXRzIHBhcmFtdGVyIDJcbiAqICAgICAgICAgXVxuICogICAgICAgfSxcbiAqXG4gKiBAY2xhc3MgW3dlYjNdIGV0aFxuICogQGNvbnN0cnVjdG9yXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBmb3JtYXR0ZXJzID0gcmVxdWlyZSgnLi9mb3JtYXR0ZXJzJyk7XG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy91dGlscycpO1xudmFyIE1ldGhvZCA9IHJlcXVpcmUoJy4vbWV0aG9kJyk7XG52YXIgUHJvcGVydHkgPSByZXF1aXJlKCcuL3Byb3BlcnR5Jyk7XG5cbnZhciBibG9ja0NhbGwgPSBmdW5jdGlvbiAoYXJncykge1xuICAgIHJldHVybiAodXRpbHMuaXNTdHJpbmcoYXJnc1swXSkgJiYgYXJnc1swXS5pbmRleE9mKCcweCcpID09PSAwKSA/IFwiZXRoX2dldEJsb2NrQnlIYXNoXCIgOiBcImV0aF9nZXRCbG9ja0J5TnVtYmVyXCI7XG59O1xuXG52YXIgdHJhbnNhY3Rpb25Gcm9tQmxvY2tDYWxsID0gZnVuY3Rpb24gKGFyZ3MpIHtcbiAgICByZXR1cm4gKHV0aWxzLmlzU3RyaW5nKGFyZ3NbMF0pICYmIGFyZ3NbMF0uaW5kZXhPZignMHgnKSA9PT0gMCkgPyAnZXRoX2dldFRyYW5zYWN0aW9uQnlCbG9ja0hhc2hBbmRJbmRleCcgOiAnZXRoX2dldFRyYW5zYWN0aW9uQnlCbG9ja051bWJlckFuZEluZGV4Jztcbn07XG5cbnZhciB1bmNsZUNhbGwgPSBmdW5jdGlvbiAoYXJncykge1xuICAgIHJldHVybiAodXRpbHMuaXNTdHJpbmcoYXJnc1swXSkgJiYgYXJnc1swXS5pbmRleE9mKCcweCcpID09PSAwKSA/ICdldGhfZ2V0VW5jbGVCeUJsb2NrSGFzaEFuZEluZGV4JyA6ICdldGhfZ2V0VW5jbGVCeUJsb2NrTnVtYmVyQW5kSW5kZXgnO1xufTtcblxudmFyIGdldEJsb2NrVHJhbnNhY3Rpb25Db3VudENhbGwgPSBmdW5jdGlvbiAoYXJncykge1xuICAgIHJldHVybiAodXRpbHMuaXNTdHJpbmcoYXJnc1swXSkgJiYgYXJnc1swXS5pbmRleE9mKCcweCcpID09PSAwKSA/ICdldGhfZ2V0QmxvY2tUcmFuc2FjdGlvbkNvdW50QnlIYXNoJyA6ICdldGhfZ2V0QmxvY2tUcmFuc2FjdGlvbkNvdW50QnlOdW1iZXInO1xufTtcblxudmFyIHVuY2xlQ291bnRDYWxsID0gZnVuY3Rpb24gKGFyZ3MpIHtcbiAgICByZXR1cm4gKHV0aWxzLmlzU3RyaW5nKGFyZ3NbMF0pICYmIGFyZ3NbMF0uaW5kZXhPZignMHgnKSA9PT0gMCkgPyAnZXRoX2dldFVuY2xlQ291bnRCeUJsb2NrSGFzaCcgOiAnZXRoX2dldFVuY2xlQ291bnRCeUJsb2NrTnVtYmVyJztcbn07XG5cbi8vLyBAcmV0dXJucyBhbiBhcnJheSBvZiBvYmplY3RzIGRlc2NyaWJpbmcgd2ViMy5ldGggYXBpIG1ldGhvZHNcblxudmFyIGdldEJhbGFuY2UgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnZ2V0QmFsYW5jZScsXG4gICAgY2FsbDogJ2V0aF9nZXRCYWxhbmNlJyxcbiAgICBwYXJhbXM6IDIsXG4gICAgaW5wdXRGb3JtYXR0ZXI6IFt1dGlscy50b0FkZHJlc3MsIGZvcm1hdHRlcnMuaW5wdXREZWZhdWx0QmxvY2tOdW1iZXJGb3JtYXR0ZXJdLFxuICAgIG91dHB1dEZvcm1hdHRlcjogZm9ybWF0dGVycy5vdXRwdXRCaWdOdW1iZXJGb3JtYXR0ZXJcbn0pO1xuXG52YXIgZ2V0U3RvcmFnZUF0ID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2dldFN0b3JhZ2VBdCcsXG4gICAgY2FsbDogJ2V0aF9nZXRTdG9yYWdlQXQnLFxuICAgIHBhcmFtczogMyxcbiAgICBpbnB1dEZvcm1hdHRlcjogW251bGwsIHV0aWxzLnRvSGV4LCBmb3JtYXR0ZXJzLmlucHV0RGVmYXVsdEJsb2NrTnVtYmVyRm9ybWF0dGVyXVxufSk7XG5cbnZhciBnZXRDb2RlID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2dldENvZGUnLFxuICAgIGNhbGw6ICdldGhfZ2V0Q29kZScsXG4gICAgcGFyYW1zOiAyLFxuICAgIGlucHV0Rm9ybWF0dGVyOiBbdXRpbHMudG9BZGRyZXNzLCBmb3JtYXR0ZXJzLmlucHV0RGVmYXVsdEJsb2NrTnVtYmVyRm9ybWF0dGVyXVxufSk7XG5cbnZhciBnZXRCbG9jayA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdnZXRCbG9jaycsXG4gICAgY2FsbDogYmxvY2tDYWxsLFxuICAgIHBhcmFtczogMixcbiAgICBpbnB1dEZvcm1hdHRlcjogW2Zvcm1hdHRlcnMuaW5wdXRCbG9ja051bWJlckZvcm1hdHRlciwgZnVuY3Rpb24gKHZhbCkgeyByZXR1cm4gISF2YWw7IH1dLFxuICAgIG91dHB1dEZvcm1hdHRlcjogZm9ybWF0dGVycy5vdXRwdXRCbG9ja0Zvcm1hdHRlclxufSk7XG5cbnZhciBnZXRVbmNsZSA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdnZXRVbmNsZScsXG4gICAgY2FsbDogdW5jbGVDYWxsLFxuICAgIHBhcmFtczogMixcbiAgICBpbnB1dEZvcm1hdHRlcjogW2Zvcm1hdHRlcnMuaW5wdXRCbG9ja051bWJlckZvcm1hdHRlciwgdXRpbHMudG9IZXhdLFxuICAgIG91dHB1dEZvcm1hdHRlcjogZm9ybWF0dGVycy5vdXRwdXRCbG9ja0Zvcm1hdHRlcixcblxufSk7XG5cbnZhciBnZXRDb21waWxlcnMgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnZ2V0Q29tcGlsZXJzJyxcbiAgICBjYWxsOiAnZXRoX2dldENvbXBpbGVycycsXG4gICAgcGFyYW1zOiAwXG59KTtcblxudmFyIGdldEJsb2NrVHJhbnNhY3Rpb25Db3VudCA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdnZXRCbG9ja1RyYW5zYWN0aW9uQ291bnQnLFxuICAgIGNhbGw6IGdldEJsb2NrVHJhbnNhY3Rpb25Db3VudENhbGwsXG4gICAgcGFyYW1zOiAxLFxuICAgIGlucHV0Rm9ybWF0dGVyOiBbZm9ybWF0dGVycy5pbnB1dEJsb2NrTnVtYmVyRm9ybWF0dGVyXSxcbiAgICBvdXRwdXRGb3JtYXR0ZXI6IHV0aWxzLnRvRGVjaW1hbFxufSk7XG5cbnZhciBnZXRCbG9ja1VuY2xlQ291bnQgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnZ2V0QmxvY2tVbmNsZUNvdW50JyxcbiAgICBjYWxsOiB1bmNsZUNvdW50Q2FsbCxcbiAgICBwYXJhbXM6IDEsXG4gICAgaW5wdXRGb3JtYXR0ZXI6IFtmb3JtYXR0ZXJzLmlucHV0QmxvY2tOdW1iZXJGb3JtYXR0ZXJdLFxuICAgIG91dHB1dEZvcm1hdHRlcjogdXRpbHMudG9EZWNpbWFsXG59KTtcblxudmFyIGdldFRyYW5zYWN0aW9uID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2dldFRyYW5zYWN0aW9uJyxcbiAgICBjYWxsOiAnZXRoX2dldFRyYW5zYWN0aW9uQnlIYXNoJyxcbiAgICBwYXJhbXM6IDEsXG4gICAgb3V0cHV0Rm9ybWF0dGVyOiBmb3JtYXR0ZXJzLm91dHB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyXG59KTtcblxudmFyIGdldFRyYW5zYWN0aW9uRnJvbUJsb2NrID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2dldFRyYW5zYWN0aW9uRnJvbUJsb2NrJyxcbiAgICBjYWxsOiB0cmFuc2FjdGlvbkZyb21CbG9ja0NhbGwsXG4gICAgcGFyYW1zOiAyLFxuICAgIGlucHV0Rm9ybWF0dGVyOiBbZm9ybWF0dGVycy5pbnB1dEJsb2NrTnVtYmVyRm9ybWF0dGVyLCB1dGlscy50b0hleF0sXG4gICAgb3V0cHV0Rm9ybWF0dGVyOiBmb3JtYXR0ZXJzLm91dHB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyXG59KTtcblxudmFyIGdldFRyYW5zYWN0aW9uQ291bnQgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnZ2V0VHJhbnNhY3Rpb25Db3VudCcsXG4gICAgY2FsbDogJ2V0aF9nZXRUcmFuc2FjdGlvbkNvdW50JyxcbiAgICBwYXJhbXM6IDIsXG4gICAgaW5wdXRGb3JtYXR0ZXI6IFtudWxsLCBmb3JtYXR0ZXJzLmlucHV0RGVmYXVsdEJsb2NrTnVtYmVyRm9ybWF0dGVyXSxcbiAgICBvdXRwdXRGb3JtYXR0ZXI6IHV0aWxzLnRvRGVjaW1hbFxufSk7XG5cbnZhciBzZW5kVHJhbnNhY3Rpb24gPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnc2VuZFRyYW5zYWN0aW9uJyxcbiAgICBjYWxsOiAnZXRoX3NlbmRUcmFuc2FjdGlvbicsXG4gICAgcGFyYW1zOiAxLFxuICAgIGlucHV0Rm9ybWF0dGVyOiBbZm9ybWF0dGVycy5pbnB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyXVxufSk7XG5cbnZhciBjYWxsID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2NhbGwnLFxuICAgIGNhbGw6ICdldGhfY2FsbCcsXG4gICAgcGFyYW1zOiAyLFxuICAgIGlucHV0Rm9ybWF0dGVyOiBbZm9ybWF0dGVycy5pbnB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyLCBmb3JtYXR0ZXJzLmlucHV0RGVmYXVsdEJsb2NrTnVtYmVyRm9ybWF0dGVyXVxufSk7XG5cbnZhciBlc3RpbWF0ZUdhcyA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdlc3RpbWF0ZUdhcycsXG4gICAgY2FsbDogJ2V0aF9lc3RpbWF0ZUdhcycsXG4gICAgcGFyYW1zOiAxLFxuICAgIGlucHV0Rm9ybWF0dGVyOiBbZm9ybWF0dGVycy5pbnB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyXSxcbiAgICBvdXRwdXRGb3JtYXR0ZXI6IHV0aWxzLnRvRGVjaW1hbFxufSk7XG5cbnZhciBjb21waWxlU29saWRpdHkgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnY29tcGlsZS5zb2xpZGl0eScsXG4gICAgY2FsbDogJ2V0aF9jb21waWxlU29saWRpdHknLFxuICAgIHBhcmFtczogMVxufSk7XG5cbnZhciBjb21waWxlTExMID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2NvbXBpbGUubGxsJyxcbiAgICBjYWxsOiAnZXRoX2NvbXBpbGVMTEwnLFxuICAgIHBhcmFtczogMVxufSk7XG5cbnZhciBjb21waWxlU2VycGVudCA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdjb21waWxlLnNlcnBlbnQnLFxuICAgIGNhbGw6ICdldGhfY29tcGlsZVNlcnBlbnQnLFxuICAgIHBhcmFtczogMVxufSk7XG5cbnZhciBzdWJtaXRXb3JrID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ3N1Ym1pdFdvcmsnLFxuICAgIGNhbGw6ICdldGhfc3VibWl0V29yaycsXG4gICAgcGFyYW1zOiAzXG59KTtcblxudmFyIGdldFdvcmsgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnZ2V0V29yaycsXG4gICAgY2FsbDogJ2V0aF9nZXRXb3JrJyxcbiAgICBwYXJhbXM6IDBcbn0pO1xuXG52YXIgbWV0aG9kcyA9IFtcbiAgICBnZXRCYWxhbmNlLFxuICAgIGdldFN0b3JhZ2VBdCxcbiAgICBnZXRDb2RlLFxuICAgIGdldEJsb2NrLFxuICAgIGdldFVuY2xlLFxuICAgIGdldENvbXBpbGVycyxcbiAgICBnZXRCbG9ja1RyYW5zYWN0aW9uQ291bnQsXG4gICAgZ2V0QmxvY2tVbmNsZUNvdW50LFxuICAgIGdldFRyYW5zYWN0aW9uLFxuICAgIGdldFRyYW5zYWN0aW9uRnJvbUJsb2NrLFxuICAgIGdldFRyYW5zYWN0aW9uQ291bnQsXG4gICAgY2FsbCxcbiAgICBlc3RpbWF0ZUdhcyxcbiAgICBzZW5kVHJhbnNhY3Rpb24sXG4gICAgY29tcGlsZVNvbGlkaXR5LFxuICAgIGNvbXBpbGVMTEwsXG4gICAgY29tcGlsZVNlcnBlbnQsXG4gICAgc3VibWl0V29yayxcbiAgICBnZXRXb3JrXG5dO1xuXG4vLy8gQHJldHVybnMgYW4gYXJyYXkgb2Ygb2JqZWN0cyBkZXNjcmliaW5nIHdlYjMuZXRoIGFwaSBwcm9wZXJ0aWVzXG5cblxuXG52YXIgcHJvcGVydGllcyA9IFtcbiAgICBuZXcgUHJvcGVydHkoe1xuICAgICAgICBuYW1lOiAnY29pbmJhc2UnLFxuICAgICAgICBnZXR0ZXI6ICdldGhfY29pbmJhc2UnXG4gICAgfSksXG4gICAgbmV3IFByb3BlcnR5KHtcbiAgICAgICAgbmFtZTogJ21pbmluZycsXG4gICAgICAgIGdldHRlcjogJ2V0aF9taW5pbmcnXG4gICAgfSksXG4gICAgbmV3IFByb3BlcnR5KHtcbiAgICAgICAgbmFtZTogJ2hhc2hyYXRlJyxcbiAgICAgICAgZ2V0dGVyOiAnZXRoX2hhc2hyYXRlJyxcbiAgICAgICAgb3V0cHV0Rm9ybWF0dGVyOiB1dGlscy50b0RlY2ltYWxcbiAgICB9KSxcbiAgICBuZXcgUHJvcGVydHkoe1xuICAgICAgICBuYW1lOiAnZ2FzUHJpY2UnLFxuICAgICAgICBnZXR0ZXI6ICdldGhfZ2FzUHJpY2UnLFxuICAgICAgICBvdXRwdXRGb3JtYXR0ZXI6IGZvcm1hdHRlcnMub3V0cHV0QmlnTnVtYmVyRm9ybWF0dGVyXG4gICAgfSksXG4gICAgbmV3IFByb3BlcnR5KHtcbiAgICAgICAgbmFtZTogJ2FjY291bnRzJyxcbiAgICAgICAgZ2V0dGVyOiAnZXRoX2FjY291bnRzJ1xuICAgIH0pLFxuICAgIG5ldyBQcm9wZXJ0eSh7XG4gICAgICAgIG5hbWU6ICdibG9ja051bWJlcicsXG4gICAgICAgIGdldHRlcjogJ2V0aF9ibG9ja051bWJlcicsXG4gICAgICAgIG91dHB1dEZvcm1hdHRlcjogdXRpbHMudG9EZWNpbWFsXG4gICAgfSlcbl07XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIG1ldGhvZHM6IG1ldGhvZHMsXG4gICAgcHJvcGVydGllczogcHJvcGVydGllc1xufTtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogXG4gKiBAZmlsZSBldmVudC5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTRcbiAqL1xuXG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy91dGlscycpO1xudmFyIGNvZGVyID0gcmVxdWlyZSgnLi4vc29saWRpdHkvY29kZXInKTtcbnZhciB3ZWIzID0gcmVxdWlyZSgnLi4vd2ViMycpO1xudmFyIGZvcm1hdHRlcnMgPSByZXF1aXJlKCcuL2Zvcm1hdHRlcnMnKTtcbnZhciBzaGEzID0gcmVxdWlyZSgnLi4vdXRpbHMvc2hhMycpO1xuXG4vKipcbiAqIFRoaXMgcHJvdG90eXBlIHNob3VsZCBiZSB1c2VkIHRvIGNyZWF0ZSBldmVudCBmaWx0ZXJzXG4gKi9cbnZhciBTb2xpZGl0eUV2ZW50ID0gZnVuY3Rpb24gKGpzb24sIGFkZHJlc3MpIHtcbiAgICB0aGlzLl9wYXJhbXMgPSBqc29uLmlucHV0cztcbiAgICB0aGlzLl9uYW1lID0gdXRpbHMudHJhbnNmb3JtVG9GdWxsTmFtZShqc29uKTtcbiAgICB0aGlzLl9hZGRyZXNzID0gYWRkcmVzcztcbiAgICB0aGlzLl9hbm9ueW1vdXMgPSBqc29uLmFub255bW91cztcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZ2V0IGZpbHRlcmVkIHBhcmFtIHR5cGVzXG4gKlxuICogQG1ldGhvZCB0eXBlc1xuICogQHBhcmFtIHtCb29sfSBkZWNpZGUgaWYgcmV0dXJuZWQgdHlwZWQgc2hvdWxkIGJlIGluZGV4ZWRcbiAqIEByZXR1cm4ge0FycmF5fSBhcnJheSBvZiB0eXBlc1xuICovXG5Tb2xpZGl0eUV2ZW50LnByb3RvdHlwZS50eXBlcyA9IGZ1bmN0aW9uIChpbmRleGVkKSB7XG4gICAgcmV0dXJuIHRoaXMuX3BhcmFtcy5maWx0ZXIoZnVuY3Rpb24gKGkpIHtcbiAgICAgICAgcmV0dXJuIGkuaW5kZXhlZCA9PT0gaW5kZXhlZDtcbiAgICB9KS5tYXAoZnVuY3Rpb24gKGkpIHtcbiAgICAgICAgcmV0dXJuIGkudHlwZTtcbiAgICB9KTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZ2V0IGV2ZW50IGRpc3BsYXkgbmFtZVxuICpcbiAqIEBtZXRob2QgZGlzcGxheU5hbWVcbiAqIEByZXR1cm4ge1N0cmluZ30gZXZlbnQgZGlzcGxheSBuYW1lXG4gKi9cblNvbGlkaXR5RXZlbnQucHJvdG90eXBlLmRpc3BsYXlOYW1lID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB1dGlscy5leHRyYWN0RGlzcGxheU5hbWUodGhpcy5fbmFtZSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGdldCBldmVudCB0eXBlIG5hbWVcbiAqXG4gKiBAbWV0aG9kIHR5cGVOYW1lXG4gKiBAcmV0dXJuIHtTdHJpbmd9IGV2ZW50IHR5cGUgbmFtZVxuICovXG5Tb2xpZGl0eUV2ZW50LnByb3RvdHlwZS50eXBlTmFtZSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdXRpbHMuZXh0cmFjdFR5cGVOYW1lKHRoaXMuX25hbWUpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBnZXQgZXZlbnQgc2lnbmF0dXJlXG4gKlxuICogQG1ldGhvZCBzaWduYXR1cmVcbiAqIEByZXR1cm4ge1N0cmluZ30gZXZlbnQgc2lnbmF0dXJlXG4gKi9cblNvbGlkaXR5RXZlbnQucHJvdG90eXBlLnNpZ25hdHVyZSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gc2hhMyh0aGlzLl9uYW1lKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZW5jb2RlIGluZGV4ZWQgcGFyYW1zIGFuZCBvcHRpb25zIHRvIG9uZSBmaW5hbCBvYmplY3RcbiAqIFxuICogQG1ldGhvZCBlbmNvZGVcbiAqIEBwYXJhbSB7T2JqZWN0fSBpbmRleGVkXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9uc1xuICogQHJldHVybiB7T2JqZWN0fSBldmVyeXRoaW5nIGNvbWJpbmVkIHRvZ2V0aGVyIGFuZCBlbmNvZGVkXG4gKi9cblNvbGlkaXR5RXZlbnQucHJvdG90eXBlLmVuY29kZSA9IGZ1bmN0aW9uIChpbmRleGVkLCBvcHRpb25zKSB7XG4gICAgaW5kZXhlZCA9IGluZGV4ZWQgfHwge307XG4gICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgdmFyIHJlc3VsdCA9IHt9O1xuXG4gICAgWydmcm9tQmxvY2snLCAndG9CbG9jayddLmZpbHRlcihmdW5jdGlvbiAoZikge1xuICAgICAgICByZXR1cm4gb3B0aW9uc1tmXSAhPT0gdW5kZWZpbmVkO1xuICAgIH0pLmZvckVhY2goZnVuY3Rpb24gKGYpIHtcbiAgICAgICAgcmVzdWx0W2ZdID0gZm9ybWF0dGVycy5pbnB1dEJsb2NrTnVtYmVyRm9ybWF0dGVyKG9wdGlvbnNbZl0pO1xuICAgIH0pO1xuXG4gICAgcmVzdWx0LnRvcGljcyA9IFtdO1xuXG4gICAgaWYgKCF0aGlzLl9hbm9ueW1vdXMpIHtcbiAgICAgICAgcmVzdWx0LmFkZHJlc3MgPSB0aGlzLl9hZGRyZXNzO1xuICAgICAgICByZXN1bHQudG9waWNzLnB1c2goJzB4JyArIHRoaXMuc2lnbmF0dXJlKCkpO1xuICAgIH1cblxuICAgIHZhciBpbmRleGVkVG9waWNzID0gdGhpcy5fcGFyYW1zLmZpbHRlcihmdW5jdGlvbiAoaSkge1xuICAgICAgICByZXR1cm4gaS5pbmRleGVkID09PSB0cnVlO1xuICAgIH0pLm1hcChmdW5jdGlvbiAoaSkge1xuICAgICAgICB2YXIgdmFsdWUgPSBpbmRleGVkW2kubmFtZV07XG4gICAgICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkIHx8IHZhbHVlID09PSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgaWYgKHV0aWxzLmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICAgICAgICByZXR1cm4gdmFsdWUubWFwKGZ1bmN0aW9uICh2KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICcweCcgKyBjb2Rlci5lbmNvZGVQYXJhbShpLnR5cGUsIHYpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICcweCcgKyBjb2Rlci5lbmNvZGVQYXJhbShpLnR5cGUsIHZhbHVlKTtcbiAgICB9KTtcblxuICAgIHJlc3VsdC50b3BpY3MgPSByZXN1bHQudG9waWNzLmNvbmNhdChpbmRleGVkVG9waWNzKTtcblxuICAgIHJldHVybiByZXN1bHQ7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGRlY29kZSBpbmRleGVkIHBhcmFtcyBhbmQgb3B0aW9uc1xuICpcbiAqIEBtZXRob2QgZGVjb2RlXG4gKiBAcGFyYW0ge09iamVjdH0gZGF0YVxuICogQHJldHVybiB7T2JqZWN0fSByZXN1bHQgb2JqZWN0IHdpdGggZGVjb2RlZCBpbmRleGVkICYmIG5vdCBpbmRleGVkIHBhcmFtc1xuICovXG5Tb2xpZGl0eUV2ZW50LnByb3RvdHlwZS5kZWNvZGUgPSBmdW5jdGlvbiAoZGF0YSkge1xuIFxuICAgIGRhdGEuZGF0YSA9IGRhdGEuZGF0YSB8fCAnJztcbiAgICBkYXRhLnRvcGljcyA9IGRhdGEudG9waWNzIHx8IFtdO1xuXG4gICAgdmFyIGFyZ1RvcGljcyA9IHRoaXMuX2Fub255bW91cyA/IGRhdGEudG9waWNzIDogZGF0YS50b3BpY3Muc2xpY2UoMSk7XG4gICAgdmFyIGluZGV4ZWREYXRhID0gYXJnVG9waWNzLm1hcChmdW5jdGlvbiAodG9waWNzKSB7IHJldHVybiB0b3BpY3Muc2xpY2UoMik7IH0pLmpvaW4oXCJcIik7XG4gICAgdmFyIGluZGV4ZWRQYXJhbXMgPSBjb2Rlci5kZWNvZGVQYXJhbXModGhpcy50eXBlcyh0cnVlKSwgaW5kZXhlZERhdGEpOyBcblxuICAgIHZhciBub3RJbmRleGVkRGF0YSA9IGRhdGEuZGF0YS5zbGljZSgyKTtcbiAgICB2YXIgbm90SW5kZXhlZFBhcmFtcyA9IGNvZGVyLmRlY29kZVBhcmFtcyh0aGlzLnR5cGVzKGZhbHNlKSwgbm90SW5kZXhlZERhdGEpO1xuICAgIFxuICAgIHZhciByZXN1bHQgPSBmb3JtYXR0ZXJzLm91dHB1dExvZ0Zvcm1hdHRlcihkYXRhKTtcbiAgICByZXN1bHQuZXZlbnQgPSB0aGlzLmRpc3BsYXlOYW1lKCk7XG4gICAgcmVzdWx0LmFkZHJlc3MgPSBkYXRhLmFkZHJlc3M7XG5cbiAgICByZXN1bHQuYXJncyA9IHRoaXMuX3BhcmFtcy5yZWR1Y2UoZnVuY3Rpb24gKGFjYywgY3VycmVudCkge1xuICAgICAgICBhY2NbY3VycmVudC5uYW1lXSA9IGN1cnJlbnQuaW5kZXhlZCA/IGluZGV4ZWRQYXJhbXMuc2hpZnQoKSA6IG5vdEluZGV4ZWRQYXJhbXMuc2hpZnQoKTtcbiAgICAgICAgcmV0dXJuIGFjYztcbiAgICB9LCB7fSk7XG5cbiAgICBkZWxldGUgcmVzdWx0LmRhdGE7XG4gICAgZGVsZXRlIHJlc3VsdC50b3BpY3M7XG5cbiAgICByZXR1cm4gcmVzdWx0O1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBjcmVhdGUgbmV3IGZpbHRlciBvYmplY3QgZnJvbSBldmVudFxuICpcbiAqIEBtZXRob2QgZXhlY3V0ZVxuICogQHBhcmFtIHtPYmplY3R9IGluZGV4ZWRcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zXG4gKiBAcmV0dXJuIHtPYmplY3R9IGZpbHRlciBvYmplY3RcbiAqL1xuU29saWRpdHlFdmVudC5wcm90b3R5cGUuZXhlY3V0ZSA9IGZ1bmN0aW9uIChpbmRleGVkLCBvcHRpb25zKSB7XG4gICAgdmFyIG8gPSB0aGlzLmVuY29kZShpbmRleGVkLCBvcHRpb25zKTtcbiAgICB2YXIgZm9ybWF0dGVyID0gdGhpcy5kZWNvZGUuYmluZCh0aGlzKTtcbiAgICByZXR1cm4gd2ViMy5ldGguZmlsdGVyKG8sIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCBmb3JtYXR0ZXIpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBhdHRhY2ggZXZlbnQgdG8gY29udHJhY3Qgb2JqZWN0XG4gKlxuICogQG1ldGhvZCBhdHRhY2hUb0NvbnRyYWN0XG4gKiBAcGFyYW0ge0NvbnRyYWN0fVxuICovXG5Tb2xpZGl0eUV2ZW50LnByb3RvdHlwZS5hdHRhY2hUb0NvbnRyYWN0ID0gZnVuY3Rpb24gKGNvbnRyYWN0KSB7XG4gICAgdmFyIGV4ZWN1dGUgPSB0aGlzLmV4ZWN1dGUuYmluZCh0aGlzKTtcbiAgICB2YXIgZGlzcGxheU5hbWUgPSB0aGlzLmRpc3BsYXlOYW1lKCk7XG4gICAgaWYgKCFjb250cmFjdFtkaXNwbGF5TmFtZV0pIHtcbiAgICAgICAgY29udHJhY3RbZGlzcGxheU5hbWVdID0gZXhlY3V0ZTtcbiAgICB9XG4gICAgY29udHJhY3RbZGlzcGxheU5hbWVdW3RoaXMudHlwZU5hbWUoKV0gPSB0aGlzLmV4ZWN1dGUuYmluZCh0aGlzLCBjb250cmFjdCk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFNvbGlkaXR5RXZlbnQ7XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqIEBmaWxlIGZpbHRlci5qc1xuICogQGF1dGhvcnM6XG4gKiAgIEplZmZyZXkgV2lsY2tlIDxqZWZmQGV0aGRldi5jb20+XG4gKiAgIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogICBNYXJpYW4gT2FuY2VhIDxtYXJpYW5AZXRoZGV2LmNvbT5cbiAqICAgRmFiaWFuIFZvZ2Vsc3RlbGxlciA8ZmFiaWFuQGV0aGRldi5jb20+XG4gKiAgIEdhdiBXb29kIDxnQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE0XG4gKi9cblxudmFyIFJlcXVlc3RNYW5hZ2VyID0gcmVxdWlyZSgnLi9yZXF1ZXN0bWFuYWdlcicpO1xudmFyIGZvcm1hdHRlcnMgPSByZXF1aXJlKCcuL2Zvcm1hdHRlcnMnKTtcbnZhciB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzL3V0aWxzJyk7XG5cbi8qKlxuKiBDb252ZXJ0cyBhIGdpdmVuIHRvcGljIHRvIGEgaGV4IHN0cmluZywgYnV0IGFsc28gYWxsb3dzIG51bGwgdmFsdWVzLlxuKlxuKiBAcGFyYW0ge01peGVkfSB2YWx1ZVxuKiBAcmV0dXJuIHtTdHJpbmd9XG4qL1xudmFyIHRvVG9waWMgPSBmdW5jdGlvbih2YWx1ZSl7XG5cbiAgICBpZih2YWx1ZSA9PT0gbnVsbCB8fCB0eXBlb2YgdmFsdWUgPT09ICd1bmRlZmluZWQnKVxuICAgICAgICByZXR1cm4gbnVsbDtcblxuICAgIHZhbHVlID0gU3RyaW5nKHZhbHVlKTtcblxuICAgIGlmKHZhbHVlLmluZGV4T2YoJzB4JykgPT09IDApXG4gICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICBlbHNlXG4gICAgICAgIHJldHVybiB1dGlscy5mcm9tQXNjaWkodmFsdWUpO1xufTtcblxuLy8vIFRoaXMgbWV0aG9kIHNob3VsZCBiZSBjYWxsZWQgb24gb3B0aW9ucyBvYmplY3QsIHRvIHZlcmlmeSBkZXByZWNhdGVkIHByb3BlcnRpZXMgJiYgbGF6eSBsb2FkIGR5bmFtaWMgb25lc1xuLy8vIEBwYXJhbSBzaG91bGQgYmUgc3RyaW5nIG9yIG9iamVjdFxuLy8vIEByZXR1cm5zIG9wdGlvbnMgc3RyaW5nIG9yIG9iamVjdFxudmFyIGdldE9wdGlvbnMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuXG4gICAgaWYgKHV0aWxzLmlzU3RyaW5nKG9wdGlvbnMpKSB7XG4gICAgICAgIHJldHVybiBvcHRpb25zO1xuICAgIH0gXG5cbiAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICAgIC8vIG1ha2Ugc3VyZSB0b3BpY3MsIGdldCBjb252ZXJ0ZWQgdG8gaGV4XG4gICAgb3B0aW9ucy50b3BpY3MgPSBvcHRpb25zLnRvcGljcyB8fCBbXTtcbiAgICBvcHRpb25zLnRvcGljcyA9IG9wdGlvbnMudG9waWNzLm1hcChmdW5jdGlvbih0b3BpYyl7XG4gICAgICAgIHJldHVybiAodXRpbHMuaXNBcnJheSh0b3BpYykpID8gdG9waWMubWFwKHRvVG9waWMpIDogdG9Ub3BpYyh0b3BpYyk7XG4gICAgfSk7XG5cbiAgICAvLyBsYXp5IGxvYWRcbiAgICByZXR1cm4ge1xuICAgICAgICB0b3BpY3M6IG9wdGlvbnMudG9waWNzLFxuICAgICAgICB0bzogb3B0aW9ucy50byxcbiAgICAgICAgYWRkcmVzczogb3B0aW9ucy5hZGRyZXNzLFxuICAgICAgICBmcm9tQmxvY2s6IGZvcm1hdHRlcnMuaW5wdXRCbG9ja051bWJlckZvcm1hdHRlcihvcHRpb25zLmZyb21CbG9jayksXG4gICAgICAgIHRvQmxvY2s6IGZvcm1hdHRlcnMuaW5wdXRCbG9ja051bWJlckZvcm1hdHRlcihvcHRpb25zLnRvQmxvY2spIFxuICAgIH07IFxufTtcblxudmFyIEZpbHRlciA9IGZ1bmN0aW9uIChvcHRpb25zLCBtZXRob2RzLCBmb3JtYXR0ZXIpIHtcbiAgICB2YXIgaW1wbGVtZW50YXRpb24gPSB7fTtcbiAgICBtZXRob2RzLmZvckVhY2goZnVuY3Rpb24gKG1ldGhvZCkge1xuICAgICAgICBtZXRob2QuYXR0YWNoVG9PYmplY3QoaW1wbGVtZW50YXRpb24pO1xuICAgIH0pO1xuICAgIHRoaXMub3B0aW9ucyA9IGdldE9wdGlvbnMob3B0aW9ucyk7XG4gICAgdGhpcy5pbXBsZW1lbnRhdGlvbiA9IGltcGxlbWVudGF0aW9uO1xuICAgIHRoaXMuY2FsbGJhY2tzID0gW107XG4gICAgdGhpcy5mb3JtYXR0ZXIgPSBmb3JtYXR0ZXI7XG4gICAgdGhpcy5maWx0ZXJJZCA9IHRoaXMuaW1wbGVtZW50YXRpb24ubmV3RmlsdGVyKHRoaXMub3B0aW9ucyk7XG59O1xuXG5GaWx0ZXIucHJvdG90eXBlLndhdGNoID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gICAgdGhpcy5jYWxsYmFja3MucHVzaChjYWxsYmFjayk7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgdmFyIG9uTWVzc2FnZSA9IGZ1bmN0aW9uIChlcnJvciwgbWVzc2FnZXMpIHtcbiAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICByZXR1cm4gc2VsZi5jYWxsYmFja3MuZm9yRWFjaChmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICBjYWxsYmFjayhlcnJvcik7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIG1lc3NhZ2VzLmZvckVhY2goZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgICAgIG1lc3NhZ2UgPSBzZWxmLmZvcm1hdHRlciA/IHNlbGYuZm9ybWF0dGVyKG1lc3NhZ2UpIDogbWVzc2FnZTtcbiAgICAgICAgICAgIHNlbGYuY2FsbGJhY2tzLmZvckVhY2goZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2sobnVsbCwgbWVzc2FnZSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIC8vIGNhbGwgZ2V0RmlsdGVyTG9ncyBvbiBzdGFydFxuICAgIGlmICghdXRpbHMuaXNTdHJpbmcodGhpcy5vcHRpb25zKSkge1xuICAgICAgICB0aGlzLmdldChmdW5jdGlvbiAoZXJyLCBtZXNzYWdlcykge1xuICAgICAgICAgICAgLy8gZG9uJ3Qgc2VuZCBhbGwgdGhlIHJlc3BvbnNlcyB0byBhbGwgdGhlIHdhdGNoZXMgYWdhaW4uLi4ganVzdCB0byB0aGlzIG9uZVxuICAgICAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKGVycik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG1lc3NhZ2VzLmZvckVhY2goZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgICAgICAgICBjYWxsYmFjayhudWxsLCBtZXNzYWdlKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBSZXF1ZXN0TWFuYWdlci5nZXRJbnN0YW5jZSgpLnN0YXJ0UG9sbGluZyh7XG4gICAgICAgIG1ldGhvZDogdGhpcy5pbXBsZW1lbnRhdGlvbi5wb2xsLmNhbGwsXG4gICAgICAgIHBhcmFtczogW3RoaXMuZmlsdGVySWRdLFxuICAgIH0sIHRoaXMuZmlsdGVySWQsIG9uTWVzc2FnZSwgdGhpcy5zdG9wV2F0Y2hpbmcuYmluZCh0aGlzKSk7XG59O1xuXG5GaWx0ZXIucHJvdG90eXBlLnN0b3BXYXRjaGluZyA9IGZ1bmN0aW9uICgpIHtcbiAgICBSZXF1ZXN0TWFuYWdlci5nZXRJbnN0YW5jZSgpLnN0b3BQb2xsaW5nKHRoaXMuZmlsdGVySWQpO1xuICAgIHRoaXMuaW1wbGVtZW50YXRpb24udW5pbnN0YWxsRmlsdGVyKHRoaXMuZmlsdGVySWQpO1xuICAgIHRoaXMuY2FsbGJhY2tzID0gW107XG59O1xuXG5GaWx0ZXIucHJvdG90eXBlLmdldCA9IGZ1bmN0aW9uIChjYWxsYmFjaykge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICBpZiAodXRpbHMuaXNGdW5jdGlvbihjYWxsYmFjaykpIHtcbiAgICAgICAgdGhpcy5pbXBsZW1lbnRhdGlvbi5nZXRMb2dzKHRoaXMuZmlsdGVySWQsIGZ1bmN0aW9uKGVyciwgcmVzKXtcbiAgICAgICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgICAgICBjYWxsYmFjayhlcnIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjYWxsYmFjayhudWxsLCByZXMubWFwKGZ1bmN0aW9uIChsb2cpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHNlbGYuZm9ybWF0dGVyID8gc2VsZi5mb3JtYXR0ZXIobG9nKSA6IGxvZztcbiAgICAgICAgICAgICAgICB9KSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBsb2dzID0gdGhpcy5pbXBsZW1lbnRhdGlvbi5nZXRMb2dzKHRoaXMuZmlsdGVySWQpO1xuICAgICAgICByZXR1cm4gbG9ncy5tYXAoZnVuY3Rpb24gKGxvZykge1xuICAgICAgICAgICAgcmV0dXJuIHNlbGYuZm9ybWF0dGVyID8gc2VsZi5mb3JtYXR0ZXIobG9nKSA6IGxvZztcbiAgICAgICAgfSk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBGaWx0ZXI7XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqIFxuICogQGZpbGUgZm9ybWF0dGVycy5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBhdXRob3IgRmFiaWFuIFZvZ2Vsc3RlbGxlciA8ZmFiaWFuQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE1XG4gKi9cblxudmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMvdXRpbHMnKTtcbnZhciBjb25maWcgPSByZXF1aXJlKCcuLi91dGlscy9jb25maWcnKTtcblxuLyoqXG4gKiBTaG91bGQgdGhlIGZvcm1hdCBvdXRwdXQgdG8gYSBiaWcgbnVtYmVyXG4gKlxuICogQG1ldGhvZCBvdXRwdXRCaWdOdW1iZXJGb3JtYXR0ZXJcbiAqIEBwYXJhbSB7U3RyaW5nfE51bWJlcnxCaWdOdW1iZXJ9XG4gKiBAcmV0dXJucyB7QmlnTnVtYmVyfSBvYmplY3RcbiAqL1xudmFyIG91dHB1dEJpZ051bWJlckZvcm1hdHRlciA9IGZ1bmN0aW9uIChudW1iZXIpIHtcbiAgICByZXR1cm4gdXRpbHMudG9CaWdOdW1iZXIobnVtYmVyKTtcbn07XG5cbnZhciBpc1ByZWRlZmluZWRCbG9ja051bWJlciA9IGZ1bmN0aW9uIChibG9ja051bWJlcikge1xuICAgIHJldHVybiBibG9ja051bWJlciA9PT0gJ2xhdGVzdCcgfHwgYmxvY2tOdW1iZXIgPT09ICdwZW5kaW5nJyB8fCBibG9ja051bWJlciA9PT0gJ2VhcmxpZXN0Jztcbn07XG5cbnZhciBpbnB1dERlZmF1bHRCbG9ja051bWJlckZvcm1hdHRlciA9IGZ1bmN0aW9uIChibG9ja051bWJlcikge1xuICAgIGlmIChibG9ja051bWJlciA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiBjb25maWcuZGVmYXVsdEJsb2NrO1xuICAgIH1cbiAgICByZXR1cm4gaW5wdXRCbG9ja051bWJlckZvcm1hdHRlcihibG9ja051bWJlcik7XG59O1xuXG52YXIgaW5wdXRCbG9ja051bWJlckZvcm1hdHRlciA9IGZ1bmN0aW9uIChibG9ja051bWJlcikge1xuICAgIGlmIChibG9ja051bWJlciA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfSBlbHNlIGlmIChpc1ByZWRlZmluZWRCbG9ja051bWJlcihibG9ja051bWJlcikpIHtcbiAgICAgICAgcmV0dXJuIGJsb2NrTnVtYmVyO1xuICAgIH1cbiAgICByZXR1cm4gdXRpbHMudG9IZXgoYmxvY2tOdW1iZXIpO1xufTtcblxuLyoqXG4gKiBGb3JtYXRzIHRoZSBpbnB1dCBvZiBhIHRyYW5zYWN0aW9uIGFuZCBjb252ZXJ0cyBhbGwgdmFsdWVzIHRvIEhFWFxuICpcbiAqIEBtZXRob2QgaW5wdXRUcmFuc2FjdGlvbkZvcm1hdHRlclxuICogQHBhcmFtIHtPYmplY3R9IHRyYW5zYWN0aW9uIG9wdGlvbnNcbiAqIEByZXR1cm5zIG9iamVjdFxuKi9cbnZhciBpbnB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyID0gZnVuY3Rpb24gKG9wdGlvbnMpe1xuXG4gICAgb3B0aW9ucy5mcm9tID0gb3B0aW9ucy5mcm9tIHx8IGNvbmZpZy5kZWZhdWx0QWNjb3VudDtcblxuICAgIC8vIG1ha2UgY29kZSAtPiBkYXRhXG4gICAgaWYgKG9wdGlvbnMuY29kZSkge1xuICAgICAgICBvcHRpb25zLmRhdGEgPSBvcHRpb25zLmNvZGU7XG4gICAgICAgIGRlbGV0ZSBvcHRpb25zLmNvZGU7XG4gICAgfVxuXG4gICAgWydnYXNQcmljZScsICdnYXMnLCAndmFsdWUnLCAnbm9uY2UnXS5maWx0ZXIoZnVuY3Rpb24gKGtleSkge1xuICAgICAgICByZXR1cm4gb3B0aW9uc1trZXldICE9PSB1bmRlZmluZWQ7XG4gICAgfSkuZm9yRWFjaChmdW5jdGlvbihrZXkpe1xuICAgICAgICBvcHRpb25zW2tleV0gPSB1dGlscy5mcm9tRGVjaW1hbChvcHRpb25zW2tleV0pO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIG9wdGlvbnM7IFxufTtcblxuLyoqXG4gKiBGb3JtYXRzIHRoZSBvdXRwdXQgb2YgYSB0cmFuc2FjdGlvbiB0byBpdHMgcHJvcGVyIHZhbHVlc1xuICogXG4gKiBAbWV0aG9kIG91dHB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyXG4gKiBAcGFyYW0ge09iamVjdH0gdHJhbnNhY3Rpb25cbiAqIEByZXR1cm5zIHtPYmplY3R9IHRyYW5zYWN0aW9uXG4qL1xudmFyIG91dHB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyID0gZnVuY3Rpb24gKHR4KXtcbiAgICB0eC5ibG9ja051bWJlciA9IHV0aWxzLnRvRGVjaW1hbCh0eC5ibG9ja051bWJlcik7XG4gICAgdHgudHJhbnNhY3Rpb25JbmRleCA9IHV0aWxzLnRvRGVjaW1hbCh0eC50cmFuc2FjdGlvbkluZGV4KTtcbiAgICB0eC5ub25jZSA9IHV0aWxzLnRvRGVjaW1hbCh0eC5ub25jZSk7XG4gICAgdHguZ2FzID0gdXRpbHMudG9EZWNpbWFsKHR4Lmdhcyk7XG4gICAgdHguZ2FzUHJpY2UgPSB1dGlscy50b0JpZ051bWJlcih0eC5nYXNQcmljZSk7XG4gICAgdHgudmFsdWUgPSB1dGlscy50b0JpZ051bWJlcih0eC52YWx1ZSk7XG4gICAgcmV0dXJuIHR4O1xufTtcblxuLyoqXG4gKiBGb3JtYXRzIHRoZSBvdXRwdXQgb2YgYSBibG9jayB0byBpdHMgcHJvcGVyIHZhbHVlc1xuICpcbiAqIEBtZXRob2Qgb3V0cHV0QmxvY2tGb3JtYXR0ZXJcbiAqIEBwYXJhbSB7T2JqZWN0fSBibG9jayBvYmplY3QgXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBibG9jayBvYmplY3RcbiovXG52YXIgb3V0cHV0QmxvY2tGb3JtYXR0ZXIgPSBmdW5jdGlvbihibG9jaykge1xuXG4gICAgLy8gdHJhbnNmb3JtIHRvIG51bWJlclxuICAgIGJsb2NrLmdhc0xpbWl0ID0gdXRpbHMudG9EZWNpbWFsKGJsb2NrLmdhc0xpbWl0KTtcbiAgICBibG9jay5nYXNVc2VkID0gdXRpbHMudG9EZWNpbWFsKGJsb2NrLmdhc1VzZWQpO1xuICAgIGJsb2NrLnNpemUgPSB1dGlscy50b0RlY2ltYWwoYmxvY2suc2l6ZSk7XG4gICAgYmxvY2sudGltZXN0YW1wID0gdXRpbHMudG9EZWNpbWFsKGJsb2NrLnRpbWVzdGFtcCk7XG4gICAgYmxvY2subnVtYmVyID0gdXRpbHMudG9EZWNpbWFsKGJsb2NrLm51bWJlcik7XG5cbiAgICBibG9jay5kaWZmaWN1bHR5ID0gdXRpbHMudG9CaWdOdW1iZXIoYmxvY2suZGlmZmljdWx0eSk7XG4gICAgYmxvY2sudG90YWxEaWZmaWN1bHR5ID0gdXRpbHMudG9CaWdOdW1iZXIoYmxvY2sudG90YWxEaWZmaWN1bHR5KTtcblxuICAgIGlmICh1dGlscy5pc0FycmF5KGJsb2NrLnRyYW5zYWN0aW9ucykpIHtcbiAgICAgICAgYmxvY2sudHJhbnNhY3Rpb25zLmZvckVhY2goZnVuY3Rpb24oaXRlbSl7XG4gICAgICAgICAgICBpZighdXRpbHMuaXNTdHJpbmcoaXRlbSkpXG4gICAgICAgICAgICAgICAgcmV0dXJuIG91dHB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyKGl0ZW0pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gYmxvY2s7XG59O1xuXG4vKipcbiAqIEZvcm1hdHMgdGhlIG91dHB1dCBvZiBhIGxvZ1xuICogXG4gKiBAbWV0aG9kIG91dHB1dExvZ0Zvcm1hdHRlclxuICogQHBhcmFtIHtPYmplY3R9IGxvZyBvYmplY3RcbiAqIEByZXR1cm5zIHtPYmplY3R9IGxvZ1xuKi9cbnZhciBvdXRwdXRMb2dGb3JtYXR0ZXIgPSBmdW5jdGlvbihsb2cpIHtcbiAgICBpZiAobG9nID09PSBudWxsKSB7IC8vICdwZW5kaW5nJyAmJiAnbGF0ZXN0JyBmaWx0ZXJzIGFyZSBudWxsc1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBsb2cuYmxvY2tOdW1iZXIgPSB1dGlscy50b0RlY2ltYWwobG9nLmJsb2NrTnVtYmVyKTtcbiAgICBsb2cudHJhbnNhY3Rpb25JbmRleCA9IHV0aWxzLnRvRGVjaW1hbChsb2cudHJhbnNhY3Rpb25JbmRleCk7XG4gICAgbG9nLmxvZ0luZGV4ID0gdXRpbHMudG9EZWNpbWFsKGxvZy5sb2dJbmRleCk7XG5cbiAgICByZXR1cm4gbG9nO1xufTtcblxuLyoqXG4gKiBGb3JtYXRzIHRoZSBpbnB1dCBvZiBhIHdoaXNwZXIgcG9zdCBhbmQgY29udmVydHMgYWxsIHZhbHVlcyB0byBIRVhcbiAqXG4gKiBAbWV0aG9kIGlucHV0UG9zdEZvcm1hdHRlclxuICogQHBhcmFtIHtPYmplY3R9IHRyYW5zYWN0aW9uIG9iamVjdFxuICogQHJldHVybnMge09iamVjdH1cbiovXG52YXIgaW5wdXRQb3N0Rm9ybWF0dGVyID0gZnVuY3Rpb24ocG9zdCkge1xuXG4gICAgcG9zdC5wYXlsb2FkID0gdXRpbHMudG9IZXgocG9zdC5wYXlsb2FkKTtcbiAgICBwb3N0LnR0bCA9IHV0aWxzLmZyb21EZWNpbWFsKHBvc3QudHRsKTtcbiAgICBwb3N0LndvcmtUb1Byb3ZlID0gdXRpbHMuZnJvbURlY2ltYWwocG9zdC53b3JrVG9Qcm92ZSk7XG4gICAgcG9zdC5wcmlvcml0eSA9IHV0aWxzLmZyb21EZWNpbWFsKHBvc3QucHJpb3JpdHkpO1xuXG4gICAgLy8gZmFsbGJhY2tcbiAgICBpZiAoIXV0aWxzLmlzQXJyYXkocG9zdC50b3BpY3MpKSB7XG4gICAgICAgIHBvc3QudG9waWNzID0gcG9zdC50b3BpY3MgPyBbcG9zdC50b3BpY3NdIDogW107XG4gICAgfVxuXG4gICAgLy8gZm9ybWF0IHRoZSBmb2xsb3dpbmcgb3B0aW9uc1xuICAgIHBvc3QudG9waWNzID0gcG9zdC50b3BpY3MubWFwKGZ1bmN0aW9uKHRvcGljKXtcbiAgICAgICAgcmV0dXJuIHV0aWxzLmZyb21Bc2NpaSh0b3BpYyk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gcG9zdDsgXG59O1xuXG4vKipcbiAqIEZvcm1hdHMgdGhlIG91dHB1dCBvZiBhIHJlY2VpdmVkIHBvc3QgbWVzc2FnZVxuICpcbiAqIEBtZXRob2Qgb3V0cHV0UG9zdEZvcm1hdHRlclxuICogQHBhcmFtIHtPYmplY3R9XG4gKiBAcmV0dXJucyB7T2JqZWN0fVxuICovXG52YXIgb3V0cHV0UG9zdEZvcm1hdHRlciA9IGZ1bmN0aW9uKHBvc3Qpe1xuXG4gICAgcG9zdC5leHBpcnkgPSB1dGlscy50b0RlY2ltYWwocG9zdC5leHBpcnkpO1xuICAgIHBvc3Quc2VudCA9IHV0aWxzLnRvRGVjaW1hbChwb3N0LnNlbnQpO1xuICAgIHBvc3QudHRsID0gdXRpbHMudG9EZWNpbWFsKHBvc3QudHRsKTtcbiAgICBwb3N0LndvcmtQcm92ZWQgPSB1dGlscy50b0RlY2ltYWwocG9zdC53b3JrUHJvdmVkKTtcbiAgICBwb3N0LnBheWxvYWRSYXcgPSBwb3N0LnBheWxvYWQ7XG4gICAgcG9zdC5wYXlsb2FkID0gdXRpbHMudG9Bc2NpaShwb3N0LnBheWxvYWQpO1xuXG4gICAgaWYgKHV0aWxzLmlzSnNvbihwb3N0LnBheWxvYWQpKSB7XG4gICAgICAgIHBvc3QucGF5bG9hZCA9IEpTT04ucGFyc2UocG9zdC5wYXlsb2FkKTtcbiAgICB9XG5cbiAgICAvLyBmb3JtYXQgdGhlIGZvbGxvd2luZyBvcHRpb25zXG4gICAgaWYgKCFwb3N0LnRvcGljcykge1xuICAgICAgICBwb3N0LnRvcGljcyA9IFtdO1xuICAgIH1cbiAgICBwb3N0LnRvcGljcyA9IHBvc3QudG9waWNzLm1hcChmdW5jdGlvbih0b3BpYyl7XG4gICAgICAgIHJldHVybiB1dGlscy50b0FzY2lpKHRvcGljKTtcbiAgICB9KTtcblxuICAgIHJldHVybiBwb3N0O1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgaW5wdXREZWZhdWx0QmxvY2tOdW1iZXJGb3JtYXR0ZXI6IGlucHV0RGVmYXVsdEJsb2NrTnVtYmVyRm9ybWF0dGVyLFxuICAgIGlucHV0QmxvY2tOdW1iZXJGb3JtYXR0ZXI6IGlucHV0QmxvY2tOdW1iZXJGb3JtYXR0ZXIsXG4gICAgaW5wdXRUcmFuc2FjdGlvbkZvcm1hdHRlcjogaW5wdXRUcmFuc2FjdGlvbkZvcm1hdHRlcixcbiAgICBpbnB1dFBvc3RGb3JtYXR0ZXI6IGlucHV0UG9zdEZvcm1hdHRlcixcbiAgICBvdXRwdXRCaWdOdW1iZXJGb3JtYXR0ZXI6IG91dHB1dEJpZ051bWJlckZvcm1hdHRlcixcbiAgICBvdXRwdXRUcmFuc2FjdGlvbkZvcm1hdHRlcjogb3V0cHV0VHJhbnNhY3Rpb25Gb3JtYXR0ZXIsXG4gICAgb3V0cHV0QmxvY2tGb3JtYXR0ZXI6IG91dHB1dEJsb2NrRm9ybWF0dGVyLFxuICAgIG91dHB1dExvZ0Zvcm1hdHRlcjogb3V0cHV0TG9nRm9ybWF0dGVyLFxuICAgIG91dHB1dFBvc3RGb3JtYXR0ZXI6IG91dHB1dFBvc3RGb3JtYXR0ZXJcbn07XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqXG4gKiBAZmlsZSBmdW5jdGlvbi5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgd2ViMyA9IHJlcXVpcmUoJy4uL3dlYjMnKTtcbnZhciBjb2RlciA9IHJlcXVpcmUoJy4uL3NvbGlkaXR5L2NvZGVyJyk7XG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy91dGlscycpO1xudmFyIHNoYTMgPSByZXF1aXJlKCcuLi91dGlscy9zaGEzJyk7XG5cbi8qKlxuICogVGhpcyBwcm90b3R5cGUgc2hvdWxkIGJlIHVzZWQgdG8gY2FsbC9zZW5kVHJhbnNhY3Rpb24gdG8gc29saWRpdHkgZnVuY3Rpb25zXG4gKi9cbnZhciBTb2xpZGl0eUZ1bmN0aW9uID0gZnVuY3Rpb24gKGpzb24sIGFkZHJlc3MpIHtcbiAgICB0aGlzLl9pbnB1dFR5cGVzID0ganNvbi5pbnB1dHMubWFwKGZ1bmN0aW9uIChpKSB7XG4gICAgICAgIHJldHVybiBpLnR5cGU7XG4gICAgfSk7XG4gICAgdGhpcy5fb3V0cHV0VHlwZXMgPSBqc29uLm91dHB1dHMubWFwKGZ1bmN0aW9uIChpKSB7XG4gICAgICAgIHJldHVybiBpLnR5cGU7XG4gICAgfSk7XG4gICAgdGhpcy5fY29uc3RhbnQgPSBqc29uLmNvbnN0YW50O1xuICAgIHRoaXMuX25hbWUgPSB1dGlscy50cmFuc2Zvcm1Ub0Z1bGxOYW1lKGpzb24pO1xuICAgIHRoaXMuX2FkZHJlc3MgPSBhZGRyZXNzO1xufTtcblxuU29saWRpdHlGdW5jdGlvbi5wcm90b3R5cGUuZXh0cmFjdENhbGxiYWNrID0gZnVuY3Rpb24gKGFyZ3MpIHtcbiAgICBpZiAodXRpbHMuaXNGdW5jdGlvbihhcmdzW2FyZ3MubGVuZ3RoIC0gMV0pKSB7XG4gICAgICAgIHJldHVybiBhcmdzLnBvcCgpOyAvLyBtb2RpZnkgdGhlIGFyZ3MgYXJyYXkhXG4gICAgfVxufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBjcmVhdGUgcGF5bG9hZCBmcm9tIGFyZ3VtZW50c1xuICpcbiAqIEBtZXRob2QgdG9QYXlsb2FkXG4gKiBAcGFyYW0ge0FycmF5fSBzb2xpZGl0eSBmdW5jdGlvbiBwYXJhbXNcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25hbCBwYXlsb2FkIG9wdGlvbnNcbiAqL1xuU29saWRpdHlGdW5jdGlvbi5wcm90b3R5cGUudG9QYXlsb2FkID0gZnVuY3Rpb24gKGFyZ3MpIHtcbiAgICB2YXIgb3B0aW9ucyA9IHt9O1xuICAgIGlmIChhcmdzLmxlbmd0aCA+IHRoaXMuX2lucHV0VHlwZXMubGVuZ3RoICYmIHV0aWxzLmlzT2JqZWN0KGFyZ3NbYXJncy5sZW5ndGggLTFdKSkge1xuICAgICAgICBvcHRpb25zID0gYXJnc1thcmdzLmxlbmd0aCAtIDFdO1xuICAgIH1cbiAgICBvcHRpb25zLnRvID0gdGhpcy5fYWRkcmVzcztcbiAgICBvcHRpb25zLmRhdGEgPSAnMHgnICsgdGhpcy5zaWduYXR1cmUoKSArIGNvZGVyLmVuY29kZVBhcmFtcyh0aGlzLl9pbnB1dFR5cGVzLCBhcmdzKTtcbiAgICByZXR1cm4gb3B0aW9ucztcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZ2V0IGZ1bmN0aW9uIHNpZ25hdHVyZVxuICpcbiAqIEBtZXRob2Qgc2lnbmF0dXJlXG4gKiBAcmV0dXJuIHtTdHJpbmd9IGZ1bmN0aW9uIHNpZ25hdHVyZVxuICovXG5Tb2xpZGl0eUZ1bmN0aW9uLnByb3RvdHlwZS5zaWduYXR1cmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHNoYTModGhpcy5fbmFtZSkuc2xpY2UoMCwgOCk7XG59O1xuXG5cblNvbGlkaXR5RnVuY3Rpb24ucHJvdG90eXBlLnVucGFja091dHB1dCA9IGZ1bmN0aW9uIChvdXRwdXQpIHtcbiAgICBpZiAoIW91dHB1dCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgb3V0cHV0ID0gb3V0cHV0Lmxlbmd0aCA+PSAyID8gb3V0cHV0LnNsaWNlKDIpIDogb3V0cHV0O1xuICAgIHZhciByZXN1bHQgPSBjb2Rlci5kZWNvZGVQYXJhbXModGhpcy5fb3V0cHV0VHlwZXMsIG91dHB1dCk7XG4gICAgcmV0dXJuIHJlc3VsdC5sZW5ndGggPT09IDEgPyByZXN1bHRbMF0gOiByZXN1bHQ7XG59O1xuXG4vKipcbiAqIENhbGxzIGEgY29udHJhY3QgZnVuY3Rpb24uXG4gKlxuICogQG1ldGhvZCBjYWxsXG4gKiBAcGFyYW0gey4uLk9iamVjdH0gQ29udHJhY3QgZnVuY3Rpb24gYXJndW1lbnRzXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBJZiB0aGUgbGFzdCBhcmd1bWVudCBpcyBhIGZ1bmN0aW9uLCB0aGUgY29udHJhY3QgZnVuY3Rpb25cbiAqICAgY2FsbCB3aWxsIGJlIGFzeW5jaHJvbm91cywgYW5kIHRoZSBjYWxsYmFjayB3aWxsIGJlIHBhc3NlZCB0aGVcbiAqICAgZXJyb3IgYW5kIHJlc3VsdC5cbiAqIEByZXR1cm4ge1N0cmluZ30gb3V0cHV0IGJ5dGVzXG4gKi9cblNvbGlkaXR5RnVuY3Rpb24ucHJvdG90eXBlLmNhbGwgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpLmZpbHRlcihmdW5jdGlvbiAoYSkge3JldHVybiBhICE9PSB1bmRlZmluZWQ7IH0pO1xuICAgIHZhciBjYWxsYmFjayA9IHRoaXMuZXh0cmFjdENhbGxiYWNrKGFyZ3MpO1xuICAgIHZhciBwYXlsb2FkID0gdGhpcy50b1BheWxvYWQoYXJncyk7XG5cbiAgICBpZiAoIWNhbGxiYWNrKSB7XG4gICAgICAgIHZhciBvdXRwdXQgPSB3ZWIzLmV0aC5jYWxsKHBheWxvYWQpO1xuICAgICAgICByZXR1cm4gdGhpcy51bnBhY2tPdXRwdXQob3V0cHV0KTtcbiAgICB9IFxuICAgICAgICBcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgd2ViMy5ldGguY2FsbChwYXlsb2FkLCBmdW5jdGlvbiAoZXJyb3IsIG91dHB1dCkge1xuICAgICAgICBjYWxsYmFjayhlcnJvciwgc2VsZi51bnBhY2tPdXRwdXQob3V0cHV0KSk7XG4gICAgfSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIHNlbmRUcmFuc2FjdGlvbiB0byBzb2xpZGl0eSBmdW5jdGlvblxuICpcbiAqIEBtZXRob2Qgc2VuZFRyYW5zYWN0aW9uXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9uc1xuICovXG5Tb2xpZGl0eUZ1bmN0aW9uLnByb3RvdHlwZS5zZW5kVHJhbnNhY3Rpb24gPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpLmZpbHRlcihmdW5jdGlvbiAoYSkge3JldHVybiBhICE9PSB1bmRlZmluZWQ7IH0pO1xuICAgIHZhciBjYWxsYmFjayA9IHRoaXMuZXh0cmFjdENhbGxiYWNrKGFyZ3MpO1xuICAgIHZhciBwYXlsb2FkID0gdGhpcy50b1BheWxvYWQoYXJncyk7XG5cbiAgICBpZiAoIWNhbGxiYWNrKSB7XG4gICAgICAgIHJldHVybiB3ZWIzLmV0aC5zZW5kVHJhbnNhY3Rpb24ocGF5bG9hZCk7XG4gICAgfVxuXG4gICAgd2ViMy5ldGguc2VuZFRyYW5zYWN0aW9uKHBheWxvYWQsIGNhbGxiYWNrKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZXN0aW1hdGVHYXMgb2Ygc29saWRpdHkgZnVuY3Rpb25cbiAqXG4gKiBAbWV0aG9kIGVzdGltYXRlR2FzXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9uc1xuICovXG5Tb2xpZGl0eUZ1bmN0aW9uLnByb3RvdHlwZS5lc3RpbWF0ZUdhcyA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cyk7XG4gICAgdmFyIGNhbGxiYWNrID0gdGhpcy5leHRyYWN0Q2FsbGJhY2soYXJncyk7XG4gICAgdmFyIHBheWxvYWQgPSB0aGlzLnRvUGF5bG9hZChhcmdzKTtcblxuICAgIGlmICghY2FsbGJhY2spIHtcbiAgICAgICAgcmV0dXJuIHdlYjMuZXRoLmVzdGltYXRlR2FzKHBheWxvYWQpO1xuICAgIH1cblxuICAgIHdlYjMuZXRoLmVzdGltYXRlR2FzKHBheWxvYWQsIGNhbGxiYWNrKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZ2V0IGZ1bmN0aW9uIGRpc3BsYXkgbmFtZVxuICpcbiAqIEBtZXRob2QgZGlzcGxheU5hbWVcbiAqIEByZXR1cm4ge1N0cmluZ30gZGlzcGxheSBuYW1lIG9mIHRoZSBmdW5jdGlvblxuICovXG5Tb2xpZGl0eUZ1bmN0aW9uLnByb3RvdHlwZS5kaXNwbGF5TmFtZSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdXRpbHMuZXh0cmFjdERpc3BsYXlOYW1lKHRoaXMuX25hbWUpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBnZXQgZnVuY3Rpb24gdHlwZSBuYW1lXG4gKlxuICogQG1ldGhvZCB0eXBlTmFtZVxuICogQHJldHVybiB7U3RyaW5nfSB0eXBlIG5hbWUgb2YgdGhlIGZ1bmN0aW9uXG4gKi9cblNvbGlkaXR5RnVuY3Rpb24ucHJvdG90eXBlLnR5cGVOYW1lID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB1dGlscy5leHRyYWN0VHlwZU5hbWUodGhpcy5fbmFtZSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZ2V0IHJwYyByZXF1ZXN0cyBmcm9tIHNvbGlkaXR5IGZ1bmN0aW9uXG4gKlxuICogQG1ldGhvZCByZXF1ZXN0XG4gKiBAcmV0dXJucyB7T2JqZWN0fVxuICovXG5Tb2xpZGl0eUZ1bmN0aW9uLnByb3RvdHlwZS5yZXF1ZXN0ID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKTtcbiAgICB2YXIgY2FsbGJhY2sgPSB0aGlzLmV4dHJhY3RDYWxsYmFjayhhcmdzKTtcbiAgICB2YXIgcGF5bG9hZCA9IHRoaXMudG9QYXlsb2FkKGFyZ3MpO1xuICAgIHZhciBmb3JtYXQgPSB0aGlzLnVucGFja091dHB1dC5iaW5kKHRoaXMpO1xuICAgIFxuICAgIHJldHVybiB7XG4gICAgICAgIGNhbGxiYWNrOiBjYWxsYmFjayxcbiAgICAgICAgcGF5bG9hZDogcGF5bG9hZCwgXG4gICAgICAgIGZvcm1hdDogZm9ybWF0XG4gICAgfTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBleGVjdXRlIGZ1bmN0aW9uXG4gKlxuICogQG1ldGhvZCBleGVjdXRlXG4gKi9cblNvbGlkaXR5RnVuY3Rpb24ucHJvdG90eXBlLmV4ZWN1dGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIHRyYW5zYWN0aW9uID0gIXRoaXMuX2NvbnN0YW50O1xuXG4gICAgLy8gc2VuZCB0cmFuc2FjdGlvblxuICAgIGlmICh0cmFuc2FjdGlvbikge1xuICAgICAgICByZXR1cm4gdGhpcy5zZW5kVHJhbnNhY3Rpb24uYXBwbHkodGhpcywgQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKSk7XG4gICAgfVxuXG4gICAgLy8gY2FsbFxuICAgIHJldHVybiB0aGlzLmNhbGwuYXBwbHkodGhpcywgQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gYXR0YWNoIGZ1bmN0aW9uIHRvIGNvbnRyYWN0XG4gKlxuICogQG1ldGhvZCBhdHRhY2hUb0NvbnRyYWN0XG4gKiBAcGFyYW0ge0NvbnRyYWN0fVxuICovXG5Tb2xpZGl0eUZ1bmN0aW9uLnByb3RvdHlwZS5hdHRhY2hUb0NvbnRyYWN0ID0gZnVuY3Rpb24gKGNvbnRyYWN0KSB7XG4gICAgdmFyIGV4ZWN1dGUgPSB0aGlzLmV4ZWN1dGUuYmluZCh0aGlzKTtcbiAgICBleGVjdXRlLnJlcXVlc3QgPSB0aGlzLnJlcXVlc3QuYmluZCh0aGlzKTtcbiAgICBleGVjdXRlLmNhbGwgPSB0aGlzLmNhbGwuYmluZCh0aGlzKTtcbiAgICBleGVjdXRlLnNlbmRUcmFuc2FjdGlvbiA9IHRoaXMuc2VuZFRyYW5zYWN0aW9uLmJpbmQodGhpcyk7XG4gICAgZXhlY3V0ZS5lc3RpbWF0ZUdhcyA9IHRoaXMuZXN0aW1hdGVHYXMuYmluZCh0aGlzKTtcbiAgICB2YXIgZGlzcGxheU5hbWUgPSB0aGlzLmRpc3BsYXlOYW1lKCk7XG4gICAgaWYgKCFjb250cmFjdFtkaXNwbGF5TmFtZV0pIHtcbiAgICAgICAgY29udHJhY3RbZGlzcGxheU5hbWVdID0gZXhlY3V0ZTtcbiAgICB9XG4gICAgY29udHJhY3RbZGlzcGxheU5hbWVdW3RoaXMudHlwZU5hbWUoKV0gPSBleGVjdXRlOyAvLyBjaXJjdWxhciEhISFcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gU29saWRpdHlGdW5jdGlvbjtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogQGZpbGUgaHR0cHByb3ZpZGVyLmpzXG4gKiBAYXV0aG9yczpcbiAqICAgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiAgIE1hcmlhbiBPYW5jZWEgPG1hcmlhbkBldGhkZXYuY29tPlxuICogICBGYWJpYW4gVm9nZWxzdGVsbGVyIDxmYWJpYW5AZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTRcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFhNTEh0dHBSZXF1ZXN0ID0gcmVxdWlyZSgneG1saHR0cHJlcXVlc3QnKS5YTUxIdHRwUmVxdWVzdDsgLy8ganNoaW50IGlnbm9yZTpsaW5lXG52YXIgZXJyb3JzID0gcmVxdWlyZSgnLi9lcnJvcnMnKTtcblxudmFyIEh0dHBQcm92aWRlciA9IGZ1bmN0aW9uIChob3N0KSB7XG4gICAgdGhpcy5ob3N0ID0gaG9zdCB8fCAnaHR0cDovL2xvY2FsaG9zdDo4NTQ1Jztcbn07XG5cbkh0dHBQcm92aWRlci5wcm90b3R5cGUuc2VuZCA9IGZ1bmN0aW9uIChwYXlsb2FkKSB7XG4gICAgdmFyIHJlcXVlc3QgPSBuZXcgWE1MSHR0cFJlcXVlc3QoKTtcblxuICAgIHJlcXVlc3Qub3BlbignUE9TVCcsIHRoaXMuaG9zdCwgZmFsc2UpO1xuICAgIFxuICAgIHRyeSB7XG4gICAgICAgIHJlcXVlc3Quc2VuZChKU09OLnN0cmluZ2lmeShwYXlsb2FkKSk7XG4gICAgfSBjYXRjaChlcnJvcikge1xuICAgICAgICB0aHJvdyBlcnJvcnMuSW52YWxpZENvbm5lY3Rpb24odGhpcy5ob3N0KTtcbiAgICB9XG5cblxuICAgIC8vIGNoZWNrIHJlcXVlc3Quc3RhdHVzXG4gICAgLy8gVE9ETzogdGhyb3cgYW4gZXJyb3IgaGVyZSEgaXQgY2Fubm90IHNpbGVudGx5IGZhaWwhISFcbiAgICAvL2lmIChyZXF1ZXN0LnN0YXR1cyAhPT0gMjAwKSB7XG4gICAgICAgIC8vcmV0dXJuO1xuICAgIC8vfVxuXG4gICAgdmFyIHJlc3VsdCA9IHJlcXVlc3QucmVzcG9uc2VUZXh0O1xuXG4gICAgdHJ5IHtcbiAgICAgICAgcmVzdWx0ID0gSlNPTi5wYXJzZShyZXN1bHQpO1xuICAgIH0gY2F0Y2goZSkge1xuICAgICAgICB0aHJvdyBlcnJvcnMuSW52YWxpZFJlc3BvbnNlKHJlc3VsdCk7ICAgICAgICAgICAgICAgIFxuICAgIH1cblxuICAgIHJldHVybiByZXN1bHQ7XG59O1xuXG5IdHRwUHJvdmlkZXIucHJvdG90eXBlLnNlbmRBc3luYyA9IGZ1bmN0aW9uIChwYXlsb2FkLCBjYWxsYmFjaykge1xuICAgIHZhciByZXF1ZXN0ID0gbmV3IFhNTEh0dHBSZXF1ZXN0KCk7XG4gICAgcmVxdWVzdC5vbnJlYWR5c3RhdGVjaGFuZ2UgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgaWYgKHJlcXVlc3QucmVhZHlTdGF0ZSA9PT0gNCkge1xuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHJlcXVlc3QucmVzcG9uc2VUZXh0O1xuICAgICAgICAgICAgdmFyIGVycm9yID0gbnVsbDtcblxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICByZXN1bHQgPSBKU09OLnBhcnNlKHJlc3VsdCk7XG4gICAgICAgICAgICB9IGNhdGNoKGUpIHtcbiAgICAgICAgICAgICAgICBlcnJvciA9IGVycm9ycy5JbnZhbGlkUmVzcG9uc2UocmVzdWx0KTsgICAgICAgICAgICAgICAgXG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNhbGxiYWNrKGVycm9yLCByZXN1bHQpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHJlcXVlc3Qub3BlbignUE9TVCcsIHRoaXMuaG9zdCwgdHJ1ZSk7XG5cbiAgICB0cnkge1xuICAgICAgICByZXF1ZXN0LnNlbmQoSlNPTi5zdHJpbmdpZnkocGF5bG9hZCkpO1xuICAgIH0gY2F0Y2goZXJyb3IpIHtcbiAgICAgICAgY2FsbGJhY2soZXJyb3JzLkludmFsaWRDb25uZWN0aW9uKHRoaXMuaG9zdCkpO1xuICAgIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gSHR0cFByb3ZpZGVyO1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBcbiAqIEBmaWxlIGljYXAuanNcbiAqIEBhdXRob3IgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE1XG4gKi9cblxudmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMvdXRpbHMnKTtcblxuLyoqXG4gKiBUaGlzIHByb3RvdHlwZSBzaG91bGQgYmUgdXNlZCB0byBleHRyYWN0IG5lY2Vzc2FyeSBpbmZvcm1hdGlvbiBmcm9tIGliYW4gYWRkcmVzc1xuICpcbiAqIEBwYXJhbSB7U3RyaW5nfSBpYmFuXG4gKi9cbnZhciBJQ0FQID0gZnVuY3Rpb24gKGliYW4pIHtcbiAgICB0aGlzLl9pYmFuID0gaWJhbjtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBjaGVjayBpZiBpY2FwIGlzIGNvcnJlY3RcbiAqXG4gKiBAbWV0aG9kIGlzVmFsaWRcbiAqIEByZXR1cm5zIHtCb29sZWFufSB0cnVlIGlmIGl0IGlzLCBvdGhlcndpc2UgZmFsc2VcbiAqL1xuSUNBUC5wcm90b3R5cGUuaXNWYWxpZCA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdXRpbHMuaXNJQkFOKHRoaXMuX2liYW4pO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGNoZWNrIGlmIGliYW4gbnVtYmVyIGlzIGRpcmVjdFxuICpcbiAqIEBtZXRob2QgaXNEaXJlY3RcbiAqIEByZXR1cm5zIHtCb29sZWFufSB0cnVlIGlmIGl0IGlzLCBvdGhlcndpc2UgZmFsc2VcbiAqL1xuSUNBUC5wcm90b3R5cGUuaXNEaXJlY3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2liYW4ubGVuZ3RoID09PSAzNDtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBjaGVjayBpZiBpYmFuIG51bWJlciBpZiBpbmRpcmVjdFxuICpcbiAqIEBtZXRob2QgaXNJbmRpcmVjdFxuICogQHJldHVybnMge0Jvb2xlYW59IHRydWUgaWYgaXQgaXMsIG90aGVyd2lzZSBmYWxzZVxuICovXG5JQ0FQLnByb3RvdHlwZS5pc0luZGlyZWN0ID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLl9pYmFuLmxlbmd0aCA9PT0gMjA7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZ2V0IGliYW4gY2hlY2tzdW1cbiAqIFVzZXMgdGhlIG1vZC05Ny0xMCBjaGVja3N1bW1pbmcgcHJvdG9jb2wgKElTTy9JRUMgNzA2NDoyMDAzKVxuICpcbiAqIEBtZXRob2QgY2hlY2tzdW1cbiAqIEByZXR1cm5zIHtTdHJpbmd9IGNoZWNrc3VtXG4gKi9cbklDQVAucHJvdG90eXBlLmNoZWNrc3VtID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLl9pYmFuLnN1YnN0cigyLCAyKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBnZXQgaW5zdGl0dXRpb24gaWRlbnRpZmllclxuICogZWcuIFhSRUdcbiAqXG4gKiBAbWV0aG9kIGluc3RpdHV0aW9uXG4gKiBAcmV0dXJucyB7U3RyaW5nfSBpbnN0aXR1dGlvbiBpZGVudGlmaWVyXG4gKi9cbklDQVAucHJvdG90eXBlLmluc3RpdHV0aW9uID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLmlzSW5kaXJlY3QoKSA/IHRoaXMuX2liYW4uc3Vic3RyKDcsIDQpIDogJyc7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZ2V0IGNsaWVudCBpZGVudGlmaWVyIHdpdGhpbiBpbnN0aXR1dGlvblxuICogZWcuIEdBVk9GWU9SS1xuICpcbiAqIEBtZXRob2QgY2xpZW50XG4gKiBAcmV0dXJucyB7U3RyaW5nfSBjbGllbnQgaWRlbnRpZmllclxuICovXG5JQ0FQLnByb3RvdHlwZS5jbGllbnQgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuaXNJbmRpcmVjdCgpID8gdGhpcy5faWJhbi5zdWJzdHIoMTEpIDogJyc7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZ2V0IGNsaWVudCBkaXJlY3QgYWRkcmVzc1xuICpcbiAqIEBtZXRob2QgYWRkcmVzc1xuICogQHJldHVybnMge1N0cmluZ30gY2xpZW50IGRpcmVjdCBhZGRyZXNzXG4gKi9cbklDQVAucHJvdG90eXBlLmFkZHJlc3MgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuaXNEaXJlY3QoKSA/IHRoaXMuX2liYW4uc3Vic3RyKDQpIDogJyc7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IElDQVA7XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqIEBmaWxlIGpzb25ycGMuanNcbiAqIEBhdXRob3JzOlxuICogICBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgSnNvbnJwYyA9IGZ1bmN0aW9uICgpIHtcbiAgICAvLyBzaW5nbGV0b24gcGF0dGVyblxuICAgIGlmIChhcmd1bWVudHMuY2FsbGVlLl9zaW5nbGV0b25JbnN0YW5jZSkge1xuICAgICAgICByZXR1cm4gYXJndW1lbnRzLmNhbGxlZS5fc2luZ2xldG9uSW5zdGFuY2U7XG4gICAgfVxuICAgIGFyZ3VtZW50cy5jYWxsZWUuX3NpbmdsZXRvbkluc3RhbmNlID0gdGhpcztcblxuICAgIHRoaXMubWVzc2FnZUlkID0gMTtcbn07XG5cbi8qKlxuICogQHJldHVybiB7SnNvbnJwY30gc2luZ2xldG9uXG4gKi9cbkpzb25ycGMuZ2V0SW5zdGFuY2UgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGluc3RhbmNlID0gbmV3IEpzb25ycGMoKTtcbiAgICByZXR1cm4gaW5zdGFuY2U7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gdmFsaWQganNvbiBjcmVhdGUgcGF5bG9hZCBvYmplY3RcbiAqXG4gKiBAbWV0aG9kIHRvUGF5bG9hZFxuICogQHBhcmFtIHtGdW5jdGlvbn0gbWV0aG9kIG9mIGpzb25ycGMgY2FsbCwgcmVxdWlyZWRcbiAqIEBwYXJhbSB7QXJyYXl9IHBhcmFtcywgYW4gYXJyYXkgb2YgbWV0aG9kIHBhcmFtcywgb3B0aW9uYWxcbiAqIEByZXR1cm5zIHtPYmplY3R9IHZhbGlkIGpzb25ycGMgcGF5bG9hZCBvYmplY3RcbiAqL1xuSnNvbnJwYy5wcm90b3R5cGUudG9QYXlsb2FkID0gZnVuY3Rpb24gKG1ldGhvZCwgcGFyYW1zKSB7XG4gICAgaWYgKCFtZXRob2QpXG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ2pzb25ycGMgbWV0aG9kIHNob3VsZCBiZSBzcGVjaWZpZWQhJyk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgICBqc29ucnBjOiAnMi4wJyxcbiAgICAgICAgbWV0aG9kOiBtZXRob2QsXG4gICAgICAgIHBhcmFtczogcGFyYW1zIHx8IFtdLFxuICAgICAgICBpZDogdGhpcy5tZXNzYWdlSWQrK1xuICAgIH07XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gY2hlY2sgaWYganNvbnJwYyByZXNwb25zZSBpcyB2YWxpZFxuICpcbiAqIEBtZXRob2QgaXNWYWxpZFJlc3BvbnNlXG4gKiBAcGFyYW0ge09iamVjdH1cbiAqIEByZXR1cm5zIHtCb29sZWFufSB0cnVlIGlmIHJlc3BvbnNlIGlzIHZhbGlkLCBvdGhlcndpc2UgZmFsc2VcbiAqL1xuSnNvbnJwYy5wcm90b3R5cGUuaXNWYWxpZFJlc3BvbnNlID0gZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgcmV0dXJuICEhcmVzcG9uc2UgJiZcbiAgICAgICAgIXJlc3BvbnNlLmVycm9yICYmXG4gICAgICAgIHJlc3BvbnNlLmpzb25ycGMgPT09ICcyLjAnICYmXG4gICAgICAgIHR5cGVvZiByZXNwb25zZS5pZCA9PT0gJ251bWJlcicgJiZcbiAgICAgICAgcmVzcG9uc2UucmVzdWx0ICE9PSB1bmRlZmluZWQ7IC8vIG9ubHkgdW5kZWZpbmVkIGlzIG5vdCB2YWxpZCBqc29uIG9iamVjdFxufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGNyZWF0ZSBiYXRjaCBwYXlsb2FkIG9iamVjdFxuICpcbiAqIEBtZXRob2QgdG9CYXRjaFBheWxvYWRcbiAqIEBwYXJhbSB7QXJyYXl9IG1lc3NhZ2VzLCBhbiBhcnJheSBvZiBvYmplY3RzIHdpdGggbWV0aG9kIChyZXF1aXJlZCkgYW5kIHBhcmFtcyAob3B0aW9uYWwpIGZpZWxkc1xuICogQHJldHVybnMge0FycmF5fSBiYXRjaCBwYXlsb2FkXG4gKi9cbkpzb25ycGMucHJvdG90eXBlLnRvQmF0Y2hQYXlsb2FkID0gZnVuY3Rpb24gKG1lc3NhZ2VzKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHJldHVybiBtZXNzYWdlcy5tYXAoZnVuY3Rpb24gKG1lc3NhZ2UpIHtcbiAgICAgICAgcmV0dXJuIHNlbGYudG9QYXlsb2FkKG1lc3NhZ2UubWV0aG9kLCBtZXNzYWdlLnBhcmFtcyk7XG4gICAgfSk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEpzb25ycGM7XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqXG4gKiBAZmlsZSBtZXRob2QuanNcbiAqIEBhdXRob3IgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE1XG4gKi9cblxudmFyIFJlcXVlc3RNYW5hZ2VyID0gcmVxdWlyZSgnLi9yZXF1ZXN0bWFuYWdlcicpO1xudmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMvdXRpbHMnKTtcbnZhciBlcnJvcnMgPSByZXF1aXJlKCcuL2Vycm9ycycpO1xuXG52YXIgTWV0aG9kID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICB0aGlzLm5hbWUgPSBvcHRpb25zLm5hbWU7XG4gICAgdGhpcy5jYWxsID0gb3B0aW9ucy5jYWxsO1xuICAgIHRoaXMucGFyYW1zID0gb3B0aW9ucy5wYXJhbXMgfHwgMDtcbiAgICB0aGlzLmlucHV0Rm9ybWF0dGVyID0gb3B0aW9ucy5pbnB1dEZvcm1hdHRlcjtcbiAgICB0aGlzLm91dHB1dEZvcm1hdHRlciA9IG9wdGlvbnMub3V0cHV0Rm9ybWF0dGVyO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBkZXRlcm1pbmUgbmFtZSBvZiB0aGUganNvbnJwYyBtZXRob2QgYmFzZWQgb24gYXJndW1lbnRzXG4gKlxuICogQG1ldGhvZCBnZXRDYWxsXG4gKiBAcGFyYW0ge0FycmF5fSBhcmd1bWVudHNcbiAqIEByZXR1cm4ge1N0cmluZ30gbmFtZSBvZiBqc29ucnBjIG1ldGhvZFxuICovXG5NZXRob2QucHJvdG90eXBlLmdldENhbGwgPSBmdW5jdGlvbiAoYXJncykge1xuICAgIHJldHVybiB1dGlscy5pc0Z1bmN0aW9uKHRoaXMuY2FsbCkgPyB0aGlzLmNhbGwoYXJncykgOiB0aGlzLmNhbGw7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGV4dHJhY3QgY2FsbGJhY2sgZnJvbSBhcnJheSBvZiBhcmd1bWVudHMuIE1vZGlmaWVzIGlucHV0IHBhcmFtXG4gKlxuICogQG1ldGhvZCBleHRyYWN0Q2FsbGJhY2tcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3VtZW50c1xuICogQHJldHVybiB7RnVuY3Rpb258TnVsbH0gY2FsbGJhY2ssIGlmIGV4aXN0c1xuICovXG5NZXRob2QucHJvdG90eXBlLmV4dHJhY3RDYWxsYmFjayA9IGZ1bmN0aW9uIChhcmdzKSB7XG4gICAgaWYgKHV0aWxzLmlzRnVuY3Rpb24oYXJnc1thcmdzLmxlbmd0aCAtIDFdKSkge1xuICAgICAgICByZXR1cm4gYXJncy5wb3AoKTsgLy8gbW9kaWZ5IHRoZSBhcmdzIGFycmF5IVxuICAgIH1cbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBjaGVjayBpZiB0aGUgbnVtYmVyIG9mIGFyZ3VtZW50cyBpcyBjb3JyZWN0XG4gKiBcbiAqIEBtZXRob2QgdmFsaWRhdGVBcmdzXG4gKiBAcGFyYW0ge0FycmF5fSBhcmd1bWVudHNcbiAqIEB0aHJvd3Mge0Vycm9yfSBpZiBpdCBpcyBub3RcbiAqL1xuTWV0aG9kLnByb3RvdHlwZS52YWxpZGF0ZUFyZ3MgPSBmdW5jdGlvbiAoYXJncykge1xuICAgIGlmIChhcmdzLmxlbmd0aCAhPT0gdGhpcy5wYXJhbXMpIHtcbiAgICAgICAgdGhyb3cgZXJyb3JzLkludmFsaWROdW1iZXJPZlBhcmFtcygpO1xuICAgIH1cbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBmb3JtYXQgaW5wdXQgYXJncyBvZiBtZXRob2RcbiAqIFxuICogQG1ldGhvZCBmb3JtYXRJbnB1dFxuICogQHBhcmFtIHtBcnJheX1cbiAqIEByZXR1cm4ge0FycmF5fVxuICovXG5NZXRob2QucHJvdG90eXBlLmZvcm1hdElucHV0ID0gZnVuY3Rpb24gKGFyZ3MpIHtcbiAgICBpZiAoIXRoaXMuaW5wdXRGb3JtYXR0ZXIpIHtcbiAgICAgICAgcmV0dXJuIGFyZ3M7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuaW5wdXRGb3JtYXR0ZXIubWFwKGZ1bmN0aW9uIChmb3JtYXR0ZXIsIGluZGV4KSB7XG4gICAgICAgIHJldHVybiBmb3JtYXR0ZXIgPyBmb3JtYXR0ZXIoYXJnc1tpbmRleF0pIDogYXJnc1tpbmRleF07XG4gICAgfSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZm9ybWF0IG91dHB1dChyZXN1bHQpIG9mIG1ldGhvZFxuICpcbiAqIEBtZXRob2QgZm9ybWF0T3V0cHV0XG4gKiBAcGFyYW0ge09iamVjdH1cbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuTWV0aG9kLnByb3RvdHlwZS5mb3JtYXRPdXRwdXQgPSBmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgcmV0dXJuIHRoaXMub3V0cHV0Rm9ybWF0dGVyICYmIHJlc3VsdCAhPT0gbnVsbCA/IHRoaXMub3V0cHV0Rm9ybWF0dGVyKHJlc3VsdCkgOiByZXN1bHQ7XG59O1xuXG4vKipcbiAqIFNob3VsZCBhdHRhY2ggZnVuY3Rpb24gdG8gbWV0aG9kXG4gKiBcbiAqIEBtZXRob2QgYXR0YWNoVG9PYmplY3RcbiAqIEBwYXJhbSB7T2JqZWN0fVxuICogQHBhcmFtIHtGdW5jdGlvbn1cbiAqL1xuTWV0aG9kLnByb3RvdHlwZS5hdHRhY2hUb09iamVjdCA9IGZ1bmN0aW9uIChvYmopIHtcbiAgICB2YXIgZnVuYyA9IHRoaXMuc2VuZC5iaW5kKHRoaXMpO1xuICAgIGZ1bmMucmVxdWVzdCA9IHRoaXMucmVxdWVzdC5iaW5kKHRoaXMpO1xuICAgIGZ1bmMuY2FsbCA9IHRoaXMuY2FsbDsgLy8gdGhhdCdzIHVnbHkuIGZpbHRlci5qcyB1c2VzIGl0XG4gICAgdmFyIG5hbWUgPSB0aGlzLm5hbWUuc3BsaXQoJy4nKTtcbiAgICBpZiAobmFtZS5sZW5ndGggPiAxKSB7XG4gICAgICAgIG9ialtuYW1lWzBdXSA9IG9ialtuYW1lWzBdXSB8fCB7fTtcbiAgICAgICAgb2JqW25hbWVbMF1dW25hbWVbMV1dID0gZnVuYztcbiAgICB9IGVsc2Uge1xuICAgICAgICBvYmpbbmFtZVswXV0gPSBmdW5jOyBcbiAgICB9XG59O1xuXG4vKipcbiAqIFNob3VsZCBjcmVhdGUgcGF5bG9hZCBmcm9tIGdpdmVuIGlucHV0IGFyZ3NcbiAqXG4gKiBAbWV0aG9kIHRvUGF5bG9hZFxuICogQHBhcmFtIHtBcnJheX0gYXJnc1xuICogQHJldHVybiB7T2JqZWN0fVxuICovXG5NZXRob2QucHJvdG90eXBlLnRvUGF5bG9hZCA9IGZ1bmN0aW9uIChhcmdzKSB7XG4gICAgdmFyIGNhbGwgPSB0aGlzLmdldENhbGwoYXJncyk7XG4gICAgdmFyIGNhbGxiYWNrID0gdGhpcy5leHRyYWN0Q2FsbGJhY2soYXJncyk7XG4gICAgdmFyIHBhcmFtcyA9IHRoaXMuZm9ybWF0SW5wdXQoYXJncyk7XG4gICAgdGhpcy52YWxpZGF0ZUFyZ3MocGFyYW1zKTtcblxuICAgIHJldHVybiB7XG4gICAgICAgIG1ldGhvZDogY2FsbCxcbiAgICAgICAgcGFyYW1zOiBwYXJhbXMsXG4gICAgICAgIGNhbGxiYWNrOiBjYWxsYmFja1xuICAgIH07XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gY3JlYXRlIHB1cmUgSlNPTlJQQyByZXF1ZXN0IHdoaWNoIGNhbiBiZSB1c2VkIGluIGJhdGNoIHJlcXVlc3RcbiAqXG4gKiBAbWV0aG9kIHJlcXVlc3RcbiAqIEBwYXJhbSB7Li4ufSBwYXJhbXNcbiAqIEByZXR1cm4ge09iamVjdH0ganNvbnJwYyByZXF1ZXN0XG4gKi9cbk1ldGhvZC5wcm90b3R5cGUucmVxdWVzdCA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgcGF5bG9hZCA9IHRoaXMudG9QYXlsb2FkKEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cykpO1xuICAgIHBheWxvYWQuZm9ybWF0ID0gdGhpcy5mb3JtYXRPdXRwdXQuYmluZCh0aGlzKTtcbiAgICByZXR1cm4gcGF5bG9hZDtcbn07XG5cbi8qKlxuICogU2hvdWxkIHNlbmQgcmVxdWVzdCB0byB0aGUgQVBJXG4gKlxuICogQG1ldGhvZCBzZW5kXG4gKiBAcGFyYW0gbGlzdCBvZiBwYXJhbXNcbiAqIEByZXR1cm4gcmVzdWx0XG4gKi9cbk1ldGhvZC5wcm90b3R5cGUuc2VuZCA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgcGF5bG9hZCA9IHRoaXMudG9QYXlsb2FkKEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cykpO1xuICAgIGlmIChwYXlsb2FkLmNhbGxiYWNrKSB7XG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgcmV0dXJuIFJlcXVlc3RNYW5hZ2VyLmdldEluc3RhbmNlKCkuc2VuZEFzeW5jKHBheWxvYWQsIGZ1bmN0aW9uIChlcnIsIHJlc3VsdCkge1xuICAgICAgICAgICAgcGF5bG9hZC5jYWxsYmFjayhlcnIsIHNlbGYuZm9ybWF0T3V0cHV0KHJlc3VsdCkpO1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuZm9ybWF0T3V0cHV0KFJlcXVlc3RNYW5hZ2VyLmdldEluc3RhbmNlKCkuc2VuZChwYXlsb2FkKSk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1ldGhvZDtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogXG4gKiBAZmlsZSBuYW1lcmVnLmpzXG4gKiBAYXV0aG9yIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbnZhciBjb250cmFjdCA9IHJlcXVpcmUoJy4vY29udHJhY3QnKTtcblxudmFyIGFkZHJlc3MgPSAnMHhjNmQ5ZDJjZDQ0OWE3NTRjNDk0MjY0ZTE4MDljNTBlMzRkNjQ1NjJiJztcblxudmFyIGFiaSA9IFtcbiAgICB7XCJjb25zdGFudFwiOnRydWUsXCJpbnB1dHNcIjpbe1wibmFtZVwiOlwiX293bmVyXCIsXCJ0eXBlXCI6XCJhZGRyZXNzXCJ9XSxcIm5hbWVcIjpcIm5hbWVcIixcIm91dHB1dHNcIjpbe1wibmFtZVwiOlwib19uYW1lXCIsXCJ0eXBlXCI6XCJieXRlczMyXCJ9XSxcInR5cGVcIjpcImZ1bmN0aW9uXCJ9LFxuICAgIHtcImNvbnN0YW50XCI6dHJ1ZSxcImlucHV0c1wiOlt7XCJuYW1lXCI6XCJfbmFtZVwiLFwidHlwZVwiOlwiYnl0ZXMzMlwifV0sXCJuYW1lXCI6XCJvd25lclwiLFwib3V0cHV0c1wiOlt7XCJuYW1lXCI6XCJcIixcInR5cGVcIjpcImFkZHJlc3NcIn1dLFwidHlwZVwiOlwiZnVuY3Rpb25cIn0sXG4gICAge1wiY29uc3RhbnRcIjp0cnVlLFwiaW5wdXRzXCI6W3tcIm5hbWVcIjpcIl9uYW1lXCIsXCJ0eXBlXCI6XCJieXRlczMyXCJ9XSxcIm5hbWVcIjpcImNvbnRlbnRcIixcIm91dHB1dHNcIjpbe1wibmFtZVwiOlwiXCIsXCJ0eXBlXCI6XCJieXRlczMyXCJ9XSxcInR5cGVcIjpcImZ1bmN0aW9uXCJ9LFxuICAgIHtcImNvbnN0YW50XCI6dHJ1ZSxcImlucHV0c1wiOlt7XCJuYW1lXCI6XCJfbmFtZVwiLFwidHlwZVwiOlwiYnl0ZXMzMlwifV0sXCJuYW1lXCI6XCJhZGRyXCIsXCJvdXRwdXRzXCI6W3tcIm5hbWVcIjpcIlwiLFwidHlwZVwiOlwiYWRkcmVzc1wifV0sXCJ0eXBlXCI6XCJmdW5jdGlvblwifSxcbiAgICB7XCJjb25zdGFudFwiOmZhbHNlLFwiaW5wdXRzXCI6W3tcIm5hbWVcIjpcIl9uYW1lXCIsXCJ0eXBlXCI6XCJieXRlczMyXCJ9XSxcIm5hbWVcIjpcInJlc2VydmVcIixcIm91dHB1dHNcIjpbXSxcInR5cGVcIjpcImZ1bmN0aW9uXCJ9LFxuICAgIHtcImNvbnN0YW50XCI6dHJ1ZSxcImlucHV0c1wiOlt7XCJuYW1lXCI6XCJfbmFtZVwiLFwidHlwZVwiOlwiYnl0ZXMzMlwifV0sXCJuYW1lXCI6XCJzdWJSZWdpc3RyYXJcIixcIm91dHB1dHNcIjpbe1wibmFtZVwiOlwib19zdWJSZWdpc3RyYXJcIixcInR5cGVcIjpcImFkZHJlc3NcIn1dLFwidHlwZVwiOlwiZnVuY3Rpb25cIn0sXG4gICAge1wiY29uc3RhbnRcIjpmYWxzZSxcImlucHV0c1wiOlt7XCJuYW1lXCI6XCJfbmFtZVwiLFwidHlwZVwiOlwiYnl0ZXMzMlwifSx7XCJuYW1lXCI6XCJfbmV3T3duZXJcIixcInR5cGVcIjpcImFkZHJlc3NcIn1dLFwibmFtZVwiOlwidHJhbnNmZXJcIixcIm91dHB1dHNcIjpbXSxcInR5cGVcIjpcImZ1bmN0aW9uXCJ9LFxuICAgIHtcImNvbnN0YW50XCI6ZmFsc2UsXCJpbnB1dHNcIjpbe1wibmFtZVwiOlwiX25hbWVcIixcInR5cGVcIjpcImJ5dGVzMzJcIn0se1wibmFtZVwiOlwiX3JlZ2lzdHJhclwiLFwidHlwZVwiOlwiYWRkcmVzc1wifV0sXCJuYW1lXCI6XCJzZXRTdWJSZWdpc3RyYXJcIixcIm91dHB1dHNcIjpbXSxcInR5cGVcIjpcImZ1bmN0aW9uXCJ9LFxuICAgIHtcImNvbnN0YW50XCI6ZmFsc2UsXCJpbnB1dHNcIjpbXSxcIm5hbWVcIjpcIlJlZ2lzdHJhclwiLFwib3V0cHV0c1wiOltdLFwidHlwZVwiOlwiZnVuY3Rpb25cIn0sXG4gICAge1wiY29uc3RhbnRcIjpmYWxzZSxcImlucHV0c1wiOlt7XCJuYW1lXCI6XCJfbmFtZVwiLFwidHlwZVwiOlwiYnl0ZXMzMlwifSx7XCJuYW1lXCI6XCJfYVwiLFwidHlwZVwiOlwiYWRkcmVzc1wifSx7XCJuYW1lXCI6XCJfcHJpbWFyeVwiLFwidHlwZVwiOlwiYm9vbFwifV0sXCJuYW1lXCI6XCJzZXRBZGRyZXNzXCIsXCJvdXRwdXRzXCI6W10sXCJ0eXBlXCI6XCJmdW5jdGlvblwifSxcbiAgICB7XCJjb25zdGFudFwiOmZhbHNlLFwiaW5wdXRzXCI6W3tcIm5hbWVcIjpcIl9uYW1lXCIsXCJ0eXBlXCI6XCJieXRlczMyXCJ9LHtcIm5hbWVcIjpcIl9jb250ZW50XCIsXCJ0eXBlXCI6XCJieXRlczMyXCJ9XSxcIm5hbWVcIjpcInNldENvbnRlbnRcIixcIm91dHB1dHNcIjpbXSxcInR5cGVcIjpcImZ1bmN0aW9uXCJ9LFxuICAgIHtcImNvbnN0YW50XCI6ZmFsc2UsXCJpbnB1dHNcIjpbe1wibmFtZVwiOlwiX25hbWVcIixcInR5cGVcIjpcImJ5dGVzMzJcIn1dLFwibmFtZVwiOlwiZGlzb3duXCIsXCJvdXRwdXRzXCI6W10sXCJ0eXBlXCI6XCJmdW5jdGlvblwifSxcbiAgICB7XCJjb25zdGFudFwiOnRydWUsXCJpbnB1dHNcIjpbe1wibmFtZVwiOlwiX25hbWVcIixcInR5cGVcIjpcImJ5dGVzMzJcIn1dLFwibmFtZVwiOlwicmVnaXN0ZXJcIixcIm91dHB1dHNcIjpbe1wibmFtZVwiOlwiXCIsXCJ0eXBlXCI6XCJhZGRyZXNzXCJ9XSxcInR5cGVcIjpcImZ1bmN0aW9uXCJ9LFxuICAgIHtcImFub255bW91c1wiOmZhbHNlLFwiaW5wdXRzXCI6W3tcImluZGV4ZWRcIjp0cnVlLFwibmFtZVwiOlwibmFtZVwiLFwidHlwZVwiOlwiYnl0ZXMzMlwifV0sXCJuYW1lXCI6XCJDaGFuZ2VkXCIsXCJ0eXBlXCI6XCJldmVudFwifSxcbiAgICB7XCJhbm9ueW1vdXNcIjpmYWxzZSxcImlucHV0c1wiOlt7XCJpbmRleGVkXCI6dHJ1ZSxcIm5hbWVcIjpcIm5hbWVcIixcInR5cGVcIjpcImJ5dGVzMzJcIn0se1wiaW5kZXhlZFwiOnRydWUsXCJuYW1lXCI6XCJhZGRyXCIsXCJ0eXBlXCI6XCJhZGRyZXNzXCJ9XSxcIm5hbWVcIjpcIlByaW1hcnlDaGFuZ2VkXCIsXCJ0eXBlXCI6XCJldmVudFwifVxuXTtcblxubW9kdWxlLmV4cG9ydHMgPSBjb250cmFjdChhYmkpLmF0KGFkZHJlc3MpO1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBAZmlsZSBldGguanNcbiAqIEBhdXRob3JzOlxuICogICBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy91dGlscycpO1xudmFyIFByb3BlcnR5ID0gcmVxdWlyZSgnLi9wcm9wZXJ0eScpO1xuXG4vLy8gQHJldHVybnMgYW4gYXJyYXkgb2Ygb2JqZWN0cyBkZXNjcmliaW5nIHdlYjMuZXRoIGFwaSBtZXRob2RzXG52YXIgbWV0aG9kcyA9IFtcbl07XG5cbi8vLyBAcmV0dXJucyBhbiBhcnJheSBvZiBvYmplY3RzIGRlc2NyaWJpbmcgd2ViMy5ldGggYXBpIHByb3BlcnRpZXNcbnZhciBwcm9wZXJ0aWVzID0gW1xuICAgIG5ldyBQcm9wZXJ0eSh7XG4gICAgICAgIG5hbWU6ICdsaXN0ZW5pbmcnLFxuICAgICAgICBnZXR0ZXI6ICduZXRfbGlzdGVuaW5nJ1xuICAgIH0pLFxuICAgIG5ldyBQcm9wZXJ0eSh7XG4gICAgICAgIG5hbWU6ICdwZWVyQ291bnQnLFxuICAgICAgICBnZXR0ZXI6ICduZXRfcGVlckNvdW50JyxcbiAgICAgICAgb3V0cHV0Rm9ybWF0dGVyOiB1dGlscy50b0RlY2ltYWxcbiAgICB9KVxuXTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBtZXRob2RzOiBtZXRob2RzLFxuICAgIHByb3BlcnRpZXM6IHByb3BlcnRpZXNcbn07XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqXG4gKiBAZmlsZSBwcm9wZXJ0eS5qc1xuICogQGF1dGhvciBGYWJpYW4gVm9nZWxzdGVsbGVyIDxmYWJpYW5AZnJvemVtYW4uZGU+XG4gKiBAYXV0aG9yIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbnZhciBSZXF1ZXN0TWFuYWdlciA9IHJlcXVpcmUoJy4vcmVxdWVzdG1hbmFnZXInKTtcblxudmFyIFByb3BlcnR5ID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICB0aGlzLm5hbWUgPSBvcHRpb25zLm5hbWU7XG4gICAgdGhpcy5nZXR0ZXIgPSBvcHRpb25zLmdldHRlcjtcbiAgICB0aGlzLnNldHRlciA9IG9wdGlvbnMuc2V0dGVyO1xuICAgIHRoaXMub3V0cHV0Rm9ybWF0dGVyID0gb3B0aW9ucy5vdXRwdXRGb3JtYXR0ZXI7XG4gICAgdGhpcy5pbnB1dEZvcm1hdHRlciA9IG9wdGlvbnMuaW5wdXRGb3JtYXR0ZXI7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZm9ybWF0IGlucHV0IGFyZ3Mgb2YgbWV0aG9kXG4gKiBcbiAqIEBtZXRob2QgZm9ybWF0SW5wdXRcbiAqIEBwYXJhbSB7QXJyYXl9XG4gKiBAcmV0dXJuIHtBcnJheX1cbiAqL1xuUHJvcGVydHkucHJvdG90eXBlLmZvcm1hdElucHV0ID0gZnVuY3Rpb24gKGFyZykge1xuICAgIHJldHVybiB0aGlzLmlucHV0Rm9ybWF0dGVyID8gdGhpcy5pbnB1dEZvcm1hdHRlcihhcmcpIDogYXJnO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGZvcm1hdCBvdXRwdXQocmVzdWx0KSBvZiBtZXRob2RcbiAqXG4gKiBAbWV0aG9kIGZvcm1hdE91dHB1dFxuICogQHBhcmFtIHtPYmplY3R9XG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cblByb3BlcnR5LnByb3RvdHlwZS5mb3JtYXRPdXRwdXQgPSBmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgcmV0dXJuIHRoaXMub3V0cHV0Rm9ybWF0dGVyICYmIHJlc3VsdCAhPT0gbnVsbCA/IHRoaXMub3V0cHV0Rm9ybWF0dGVyKHJlc3VsdCkgOiByZXN1bHQ7XG59O1xuXG4vKipcbiAqIFNob3VsZCBhdHRhY2ggZnVuY3Rpb24gdG8gbWV0aG9kXG4gKiBcbiAqIEBtZXRob2QgYXR0YWNoVG9PYmplY3RcbiAqIEBwYXJhbSB7T2JqZWN0fVxuICogQHBhcmFtIHtGdW5jdGlvbn1cbiAqL1xuUHJvcGVydHkucHJvdG90eXBlLmF0dGFjaFRvT2JqZWN0ID0gZnVuY3Rpb24gKG9iaikge1xuICAgIHZhciBwcm90byA9IHtcbiAgICAgICAgZ2V0OiB0aGlzLmdldC5iaW5kKHRoaXMpLFxuICAgIH07XG5cbiAgICB2YXIgbmFtZXMgPSB0aGlzLm5hbWUuc3BsaXQoJy4nKTtcbiAgICB2YXIgbmFtZSA9IG5hbWVzWzBdO1xuICAgIGlmIChuYW1lcy5sZW5ndGggPiAxKSB7XG4gICAgICAgIG9ialtuYW1lc1swXV0gPSBvYmpbbmFtZXNbMF1dIHx8IHt9O1xuICAgICAgICBvYmogPSBvYmpbbmFtZXNbMF1dO1xuICAgICAgICBuYW1lID0gbmFtZXNbMV07XG4gICAgfVxuICAgIFxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShvYmosIG5hbWUsIHByb3RvKTtcblxuICAgIHZhciB0b0FzeW5jTmFtZSA9IGZ1bmN0aW9uIChwcmVmaXgsIG5hbWUpIHtcbiAgICAgICAgcmV0dXJuIHByZWZpeCArIG5hbWUuY2hhckF0KDApLnRvVXBwZXJDYXNlKCkgKyBuYW1lLnNsaWNlKDEpO1xuICAgIH07XG5cbiAgICBvYmpbdG9Bc3luY05hbWUoJ2dldCcsIG5hbWUpXSA9IHRoaXMuZ2V0QXN5bmMuYmluZCh0aGlzKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZ2V0IHZhbHVlIG9mIHRoZSBwcm9wZXJ0eVxuICpcbiAqIEBtZXRob2QgZ2V0XG4gKiBAcmV0dXJuIHtPYmplY3R9IHZhbHVlIG9mIHRoZSBwcm9wZXJ0eVxuICovXG5Qcm9wZXJ0eS5wcm90b3R5cGUuZ2V0ID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLmZvcm1hdE91dHB1dChSZXF1ZXN0TWFuYWdlci5nZXRJbnN0YW5jZSgpLnNlbmQoe1xuICAgICAgICBtZXRob2Q6IHRoaXMuZ2V0dGVyXG4gICAgfSkpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBhc3luY2hyb3Vub3VzbHkgZ2V0IHZhbHVlIG9mIHByb3BlcnR5XG4gKlxuICogQG1ldGhvZCBnZXRBc3luY1xuICogQHBhcmFtIHtGdW5jdGlvbn1cbiAqL1xuUHJvcGVydHkucHJvdG90eXBlLmdldEFzeW5jID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIFJlcXVlc3RNYW5hZ2VyLmdldEluc3RhbmNlKCkuc2VuZEFzeW5jKHtcbiAgICAgICAgbWV0aG9kOiB0aGlzLmdldHRlclxuICAgIH0sIGZ1bmN0aW9uIChlcnIsIHJlc3VsdCkge1xuICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICByZXR1cm4gY2FsbGJhY2soZXJyKTtcbiAgICAgICAgfVxuICAgICAgICBjYWxsYmFjayhlcnIsIHNlbGYuZm9ybWF0T3V0cHV0KHJlc3VsdCkpO1xuICAgIH0pO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBQcm9wZXJ0eTtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogQGZpbGUgcXRzeW5jLmpzXG4gKiBAYXV0aG9yczpcbiAqICAgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiAgIE1hcmlhbiBPYW5jZWEgPG1hcmlhbkBldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNFxuICovXG5cbnZhciBRdFN5bmNQcm92aWRlciA9IGZ1bmN0aW9uICgpIHtcbn07XG5cblF0U3luY1Byb3ZpZGVyLnByb3RvdHlwZS5zZW5kID0gZnVuY3Rpb24gKHBheWxvYWQpIHtcbiAgICB2YXIgcmVzdWx0ID0gbmF2aWdhdG9yLnF0LmNhbGxNZXRob2QoSlNPTi5zdHJpbmdpZnkocGF5bG9hZCkpO1xuICAgIHJldHVybiBKU09OLnBhcnNlKHJlc3VsdCk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFF0U3luY1Byb3ZpZGVyO1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBcbiAqIEBmaWxlIHJlcXVlc3RtYW5hZ2VyLmpzXG4gKiBAYXV0aG9yIEplZmZyZXkgV2lsY2tlIDxqZWZmQGV0aGRldi5jb20+XG4gKiBAYXV0aG9yIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGF1dGhvciBNYXJpYW4gT2FuY2VhIDxtYXJpYW5AZXRoZGV2LmNvbT5cbiAqIEBhdXRob3IgRmFiaWFuIFZvZ2Vsc3RlbGxlciA8ZmFiaWFuQGV0aGRldi5jb20+XG4gKiBAYXV0aG9yIEdhdiBXb29kIDxnQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE0XG4gKi9cblxudmFyIEpzb25ycGMgPSByZXF1aXJlKCcuL2pzb25ycGMnKTtcbnZhciB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzL3V0aWxzJyk7XG52YXIgYyA9IHJlcXVpcmUoJy4uL3V0aWxzL2NvbmZpZycpO1xudmFyIGVycm9ycyA9IHJlcXVpcmUoJy4vZXJyb3JzJyk7XG5cbi8qKlxuICogSXQncyByZXNwb25zaWJsZSBmb3IgcGFzc2luZyBtZXNzYWdlcyB0byBwcm92aWRlcnNcbiAqIEl0J3MgYWxzbyByZXNwb25zaWJsZSBmb3IgcG9sbGluZyB0aGUgZXRoZXJldW0gbm9kZSBmb3IgaW5jb21pbmcgbWVzc2FnZXNcbiAqIERlZmF1bHQgcG9sbCB0aW1lb3V0IGlzIDEgc2Vjb25kXG4gKiBTaW5nbGV0b25cbiAqL1xudmFyIFJlcXVlc3RNYW5hZ2VyID0gZnVuY3Rpb24gKHByb3ZpZGVyKSB7XG4gICAgLy8gc2luZ2xldG9uIHBhdHRlcm5cbiAgICBpZiAoYXJndW1lbnRzLmNhbGxlZS5fc2luZ2xldG9uSW5zdGFuY2UpIHtcbiAgICAgICAgcmV0dXJuIGFyZ3VtZW50cy5jYWxsZWUuX3NpbmdsZXRvbkluc3RhbmNlO1xuICAgIH1cbiAgICBhcmd1bWVudHMuY2FsbGVlLl9zaW5nbGV0b25JbnN0YW5jZSA9IHRoaXM7XG5cbiAgICB0aGlzLnByb3ZpZGVyID0gcHJvdmlkZXI7XG4gICAgdGhpcy5wb2xscyA9IFtdO1xuICAgIHRoaXMudGltZW91dCA9IG51bGw7XG4gICAgdGhpcy5wb2xsKCk7XG59O1xuXG4vKipcbiAqIEByZXR1cm4ge1JlcXVlc3RNYW5hZ2VyfSBzaW5nbGV0b25cbiAqL1xuUmVxdWVzdE1hbmFnZXIuZ2V0SW5zdGFuY2UgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGluc3RhbmNlID0gbmV3IFJlcXVlc3RNYW5hZ2VyKCk7XG4gICAgcmV0dXJuIGluc3RhbmNlO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBzeW5jaHJvbm91c2x5IHNlbmQgcmVxdWVzdFxuICpcbiAqIEBtZXRob2Qgc2VuZFxuICogQHBhcmFtIHtPYmplY3R9IGRhdGFcbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuUmVxdWVzdE1hbmFnZXIucHJvdG90eXBlLnNlbmQgPSBmdW5jdGlvbiAoZGF0YSkge1xuICAgIGlmICghdGhpcy5wcm92aWRlcikge1xuICAgICAgICBjb25zb2xlLmVycm9yKGVycm9ycy5JbnZhbGlkUHJvdmlkZXIoKSk7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHZhciBwYXlsb2FkID0gSnNvbnJwYy5nZXRJbnN0YW5jZSgpLnRvUGF5bG9hZChkYXRhLm1ldGhvZCwgZGF0YS5wYXJhbXMpO1xuICAgIHZhciByZXN1bHQgPSB0aGlzLnByb3ZpZGVyLnNlbmQocGF5bG9hZCk7XG5cbiAgICBpZiAoIUpzb25ycGMuZ2V0SW5zdGFuY2UoKS5pc1ZhbGlkUmVzcG9uc2UocmVzdWx0KSkge1xuICAgICAgICB0aHJvdyBlcnJvcnMuSW52YWxpZFJlc3BvbnNlKHJlc3VsdCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdC5yZXN1bHQ7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGFzeW5jaHJvbm91c2x5IHNlbmQgcmVxdWVzdFxuICpcbiAqIEBtZXRob2Qgc2VuZEFzeW5jXG4gKiBAcGFyYW0ge09iamVjdH0gZGF0YVxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2tcbiAqL1xuUmVxdWVzdE1hbmFnZXIucHJvdG90eXBlLnNlbmRBc3luYyA9IGZ1bmN0aW9uIChkYXRhLCBjYWxsYmFjaykge1xuICAgIGlmICghdGhpcy5wcm92aWRlcikge1xuICAgICAgICByZXR1cm4gY2FsbGJhY2soZXJyb3JzLkludmFsaWRQcm92aWRlcigpKTtcbiAgICB9XG5cbiAgICB2YXIgcGF5bG9hZCA9IEpzb25ycGMuZ2V0SW5zdGFuY2UoKS50b1BheWxvYWQoZGF0YS5tZXRob2QsIGRhdGEucGFyYW1zKTtcbiAgICB0aGlzLnByb3ZpZGVyLnNlbmRBc3luYyhwYXlsb2FkLCBmdW5jdGlvbiAoZXJyLCByZXN1bHQpIHtcbiAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgcmV0dXJuIGNhbGxiYWNrKGVycik7XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIGlmICghSnNvbnJwYy5nZXRJbnN0YW5jZSgpLmlzVmFsaWRSZXNwb25zZShyZXN1bHQpKSB7XG4gICAgICAgICAgICByZXR1cm4gY2FsbGJhY2soZXJyb3JzLkludmFsaWRSZXNwb25zZShyZXN1bHQpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNhbGxiYWNrKG51bGwsIHJlc3VsdC5yZXN1bHQpO1xuICAgIH0pO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGFzeW5jaHJvbm91c2x5IHNlbmQgYmF0Y2ggcmVxdWVzdFxuICpcbiAqIEBtZXRob2Qgc2VuZEJhdGNoXG4gKiBAcGFyYW0ge0FycmF5fSBiYXRjaCBkYXRhXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFja1xuICovXG5SZXF1ZXN0TWFuYWdlci5wcm90b3R5cGUuc2VuZEJhdGNoID0gZnVuY3Rpb24gKGRhdGEsIGNhbGxiYWNrKSB7XG4gICAgaWYgKCF0aGlzLnByb3ZpZGVyKSB7XG4gICAgICAgIHJldHVybiBjYWxsYmFjayhlcnJvcnMuSW52YWxpZFByb3ZpZGVyKCkpO1xuICAgIH1cblxuICAgIHZhciBwYXlsb2FkID0gSnNvbnJwYy5nZXRJbnN0YW5jZSgpLnRvQmF0Y2hQYXlsb2FkKGRhdGEpO1xuXG4gICAgdGhpcy5wcm92aWRlci5zZW5kQXN5bmMocGF5bG9hZCwgZnVuY3Rpb24gKGVyciwgcmVzdWx0cykge1xuICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICByZXR1cm4gY2FsbGJhY2soZXJyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghdXRpbHMuaXNBcnJheShyZXN1bHRzKSkge1xuICAgICAgICAgICAgcmV0dXJuIGNhbGxiYWNrKGVycm9ycy5JbnZhbGlkUmVzcG9uc2UocmVzdWx0cykpO1xuICAgICAgICB9XG5cbiAgICAgICAgY2FsbGJhY2soZXJyLCByZXN1bHRzKTtcbiAgICB9KTsgXG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIHNldCBwcm92aWRlciBvZiByZXF1ZXN0IG1hbmFnZXJcbiAqXG4gKiBAbWV0aG9kIHNldFByb3ZpZGVyXG4gKiBAcGFyYW0ge09iamVjdH1cbiAqL1xuUmVxdWVzdE1hbmFnZXIucHJvdG90eXBlLnNldFByb3ZpZGVyID0gZnVuY3Rpb24gKHApIHtcbiAgICB0aGlzLnByb3ZpZGVyID0gcDtcbn07XG5cbi8qanNoaW50IG1heHBhcmFtczo0ICovXG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gc3RhcnQgcG9sbGluZ1xuICpcbiAqIEBtZXRob2Qgc3RhcnRQb2xsaW5nXG4gKiBAcGFyYW0ge09iamVjdH0gZGF0YVxuICogQHBhcmFtIHtOdW1iZXJ9IHBvbGxJZFxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2tcbiAqIEBwYXJhbSB7RnVuY3Rpb259IHVuaW5zdGFsbFxuICpcbiAqIEB0b2RvIGNsZWFudXAgbnVtYmVyIG9mIHBhcmFtc1xuICovXG5SZXF1ZXN0TWFuYWdlci5wcm90b3R5cGUuc3RhcnRQb2xsaW5nID0gZnVuY3Rpb24gKGRhdGEsIHBvbGxJZCwgY2FsbGJhY2ssIHVuaW5zdGFsbCkge1xuICAgIHRoaXMucG9sbHMucHVzaCh7ZGF0YTogZGF0YSwgaWQ6IHBvbGxJZCwgY2FsbGJhY2s6IGNhbGxiYWNrLCB1bmluc3RhbGw6IHVuaW5zdGFsbH0pO1xufTtcbi8qanNoaW50IG1heHBhcmFtczozICovXG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gc3RvcCBwb2xsaW5nIGZvciBmaWx0ZXIgd2l0aCBnaXZlbiBpZFxuICpcbiAqIEBtZXRob2Qgc3RvcFBvbGxpbmdcbiAqIEBwYXJhbSB7TnVtYmVyfSBwb2xsSWRcbiAqL1xuUmVxdWVzdE1hbmFnZXIucHJvdG90eXBlLnN0b3BQb2xsaW5nID0gZnVuY3Rpb24gKHBvbGxJZCkge1xuICAgIGZvciAodmFyIGkgPSB0aGlzLnBvbGxzLmxlbmd0aDsgaS0tOykge1xuICAgICAgICB2YXIgcG9sbCA9IHRoaXMucG9sbHNbaV07XG4gICAgICAgIGlmIChwb2xsLmlkID09PSBwb2xsSWQpIHtcbiAgICAgICAgICAgIHRoaXMucG9sbHMuc3BsaWNlKGksIDEpO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIHJlc2V0IHBvbGxpbmcgbWVjaGFuaXNtIG9mIHJlcXVlc3QgbWFuYWdlclxuICpcbiAqIEBtZXRob2QgcmVzZXRcbiAqL1xuUmVxdWVzdE1hbmFnZXIucHJvdG90eXBlLnJlc2V0ID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMucG9sbHMuZm9yRWFjaChmdW5jdGlvbiAocG9sbCkge1xuICAgICAgICBwb2xsLnVuaW5zdGFsbChwb2xsLmlkKTsgXG4gICAgfSk7XG4gICAgdGhpcy5wb2xscyA9IFtdO1xuXG4gICAgaWYgKHRoaXMudGltZW91dCkge1xuICAgICAgICBjbGVhclRpbWVvdXQodGhpcy50aW1lb3V0KTtcbiAgICAgICAgdGhpcy50aW1lb3V0ID0gbnVsbDtcbiAgICB9XG4gICAgdGhpcy5wb2xsKCk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gcG9sbCBmb3IgY2hhbmdlcyBvbiBmaWx0ZXIgd2l0aCBnaXZlbiBpZFxuICpcbiAqIEBtZXRob2QgcG9sbFxuICovXG5SZXF1ZXN0TWFuYWdlci5wcm90b3R5cGUucG9sbCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnRpbWVvdXQgPSBzZXRUaW1lb3V0KHRoaXMucG9sbC5iaW5kKHRoaXMpLCBjLkVUSF9QT0xMSU5HX1RJTUVPVVQpO1xuXG4gICAgaWYgKCF0aGlzLnBvbGxzLmxlbmd0aCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLnByb3ZpZGVyKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3JzLkludmFsaWRQcm92aWRlcigpKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHZhciBwYXlsb2FkID0gSnNvbnJwYy5nZXRJbnN0YW5jZSgpLnRvQmF0Y2hQYXlsb2FkKHRoaXMucG9sbHMubWFwKGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICAgIHJldHVybiBkYXRhLmRhdGE7XG4gICAgfSkpO1xuXG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHRoaXMucHJvdmlkZXIuc2VuZEFzeW5jKHBheWxvYWQsIGZ1bmN0aW9uIChlcnJvciwgcmVzdWx0cykge1xuICAgICAgICAvLyBUT0RPOiBjb25zb2xlIGxvZz9cbiAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgICAgIFxuICAgICAgICBpZiAoIXV0aWxzLmlzQXJyYXkocmVzdWx0cykpIHtcbiAgICAgICAgICAgIHRocm93IGVycm9ycy5JbnZhbGlkUmVzcG9uc2UocmVzdWx0cyk7XG4gICAgICAgIH1cblxuICAgICAgICByZXN1bHRzLm1hcChmdW5jdGlvbiAocmVzdWx0LCBpbmRleCkge1xuICAgICAgICAgICAgcmVzdWx0LmNhbGxiYWNrID0gc2VsZi5wb2xsc1tpbmRleF0uY2FsbGJhY2s7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9KS5maWx0ZXIoZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgdmFyIHZhbGlkID0gSnNvbnJwYy5nZXRJbnN0YW5jZSgpLmlzVmFsaWRSZXNwb25zZShyZXN1bHQpO1xuICAgICAgICAgICAgaWYgKCF2YWxpZCkge1xuICAgICAgICAgICAgICAgIHJlc3VsdC5jYWxsYmFjayhlcnJvcnMuSW52YWxpZFJlc3BvbnNlKHJlc3VsdCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHZhbGlkO1xuICAgICAgICB9KS5maWx0ZXIoZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgcmV0dXJuIHV0aWxzLmlzQXJyYXkocmVzdWx0LnJlc3VsdCkgJiYgcmVzdWx0LnJlc3VsdC5sZW5ndGggPiAwO1xuICAgICAgICB9KS5mb3JFYWNoKGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgICAgIHJlc3VsdC5jYWxsYmFjayhudWxsLCByZXN1bHQucmVzdWx0KTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlcXVlc3RNYW5hZ2VyO1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBAZmlsZSBzaGguanNcbiAqIEBhdXRob3JzOlxuICogICBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgTWV0aG9kID0gcmVxdWlyZSgnLi9tZXRob2QnKTtcbnZhciBmb3JtYXR0ZXJzID0gcmVxdWlyZSgnLi9mb3JtYXR0ZXJzJyk7XG5cbnZhciBwb3N0ID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ3Bvc3QnLCBcbiAgICBjYWxsOiAnc2hoX3Bvc3QnLCBcbiAgICBwYXJhbXM6IDEsXG4gICAgaW5wdXRGb3JtYXR0ZXI6IFtmb3JtYXR0ZXJzLmlucHV0UG9zdEZvcm1hdHRlcl1cbn0pO1xuXG52YXIgbmV3SWRlbnRpdHkgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnbmV3SWRlbnRpdHknLFxuICAgIGNhbGw6ICdzaGhfbmV3SWRlbnRpdHknLFxuICAgIHBhcmFtczogMFxufSk7XG5cbnZhciBoYXNJZGVudGl0eSA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdoYXNJZGVudGl0eScsXG4gICAgY2FsbDogJ3NoaF9oYXNJZGVudGl0eScsXG4gICAgcGFyYW1zOiAxXG59KTtcblxudmFyIG5ld0dyb3VwID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ25ld0dyb3VwJyxcbiAgICBjYWxsOiAnc2hoX25ld0dyb3VwJyxcbiAgICBwYXJhbXM6IDBcbn0pO1xuXG52YXIgYWRkVG9Hcm91cCA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdhZGRUb0dyb3VwJyxcbiAgICBjYWxsOiAnc2hoX2FkZFRvR3JvdXAnLFxuICAgIHBhcmFtczogMFxufSk7XG5cbnZhciBtZXRob2RzID0gW1xuICAgIHBvc3QsXG4gICAgbmV3SWRlbnRpdHksXG4gICAgaGFzSWRlbnRpdHksXG4gICAgbmV3R3JvdXAsXG4gICAgYWRkVG9Hcm91cFxuXTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgbWV0aG9kczogbWV0aG9kc1xufTtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogXG4gKiBAZmlsZSB0cmFuc2Zlci5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgd2ViMyA9IHJlcXVpcmUoJy4uL3dlYjMnKTtcbnZhciBJQ0FQID0gcmVxdWlyZSgnLi9pY2FwJyk7XG52YXIgbmFtZXJlZyA9IHJlcXVpcmUoJy4vbmFtZXJlZycpO1xudmFyIGNvbnRyYWN0ID0gcmVxdWlyZSgnLi9jb250cmFjdCcpO1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIG1ha2UgSUNBUCB0cmFuc2ZlclxuICpcbiAqIEBtZXRob2QgdHJhbnNmZXJcbiAqIEBwYXJhbSB7U3RyaW5nfSBpYmFuIG51bWJlclxuICogQHBhcmFtIHtTdHJpbmd9IGZyb20gKGFkZHJlc3MpXG4gKiBAcGFyYW0ge1ZhbHVlfSB2YWx1ZSB0byBiZSB0cmFuZmVyZWRcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrLCBjYWxsYmFja1xuICovXG52YXIgdHJhbnNmZXIgPSBmdW5jdGlvbiAoZnJvbSwgaWJhbiwgdmFsdWUsIGNhbGxiYWNrKSB7XG4gICAgdmFyIGljYXAgPSBuZXcgSUNBUChpYmFuKTsgXG4gICAgaWYgKCFpY2FwLmlzVmFsaWQoKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgaWJhbiBhZGRyZXNzJyk7XG4gICAgfVxuXG4gICAgaWYgKGljYXAuaXNEaXJlY3QoKSkge1xuICAgICAgICByZXR1cm4gdHJhbnNmZXJUb0FkZHJlc3MoZnJvbSwgaWNhcC5hZGRyZXNzKCksIHZhbHVlLCBjYWxsYmFjayk7XG4gICAgfVxuICAgIFxuICAgIGlmICghY2FsbGJhY2spIHtcbiAgICAgICAgdmFyIGFkZHJlc3MgPSBuYW1lcmVnLmFkZHIoaWNhcC5pbnN0aXR1dGlvbigpKTtcbiAgICAgICAgcmV0dXJuIGRlcG9zaXQoZnJvbSwgYWRkcmVzcywgdmFsdWUsIGljYXAuY2xpZW50KCkpO1xuICAgIH1cblxuICAgIG5hbWVyZWcuYWRkcihpY2FwLmluc2l0dXRpb24oKSwgZnVuY3Rpb24gKGVyciwgYWRkcmVzcykge1xuICAgICAgICByZXR1cm4gZGVwb3NpdChmcm9tLCBhZGRyZXNzLCB2YWx1ZSwgaWNhcC5jbGllbnQoKSwgY2FsbGJhY2spO1xuICAgIH0pO1xuICAgIFxufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byB0cmFuc2ZlciBmdW5kcyB0byBjZXJ0YWluIGFkZHJlc3NcbiAqXG4gKiBAbWV0aG9kIHRyYW5zZmVyVG9BZGRyZXNzXG4gKiBAcGFyYW0ge1N0cmluZ30gYWRkcmVzc1xuICogQHBhcmFtIHtTdHJpbmd9IGZyb20gKGFkZHJlc3MpXG4gKiBAcGFyYW0ge1ZhbHVlfSB2YWx1ZSB0byBiZSB0cmFuZmVyZWRcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrLCBjYWxsYmFja1xuICovXG52YXIgdHJhbnNmZXJUb0FkZHJlc3MgPSBmdW5jdGlvbiAoZnJvbSwgYWRkcmVzcywgdmFsdWUsIGNhbGxiYWNrKSB7XG4gICAgcmV0dXJuIHdlYjMuZXRoLnNlbmRUcmFuc2FjdGlvbih7XG4gICAgICAgIGFkZHJlc3M6IGFkZHJlc3MsXG4gICAgICAgIGZyb206IGZyb20sXG4gICAgICAgIHZhbHVlOiB2YWx1ZVxuICAgIH0sIGNhbGxiYWNrKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZGVwb3NpdCBmdW5kcyB0byBnZW5lcmljIEV4Y2hhbmdlIGNvbnRyYWN0IChtdXN0IGltcGxlbWVudCBkZXBvc2l0KGJ5dGVzMzIpIG1ldGhvZCEpXG4gKlxuICogQG1ldGhvZCBkZXBvc2l0XG4gKiBAcGFyYW0ge1N0cmluZ30gYWRkcmVzc1xuICogQHBhcmFtIHtTdHJpbmd9IGZyb20gKGFkZHJlc3MpXG4gKiBAcGFyYW0ge1ZhbHVlfSB2YWx1ZSB0byBiZSB0cmFuZmVyZWRcbiAqIEBwYXJhbSB7U3RyaW5nfSBjbGllbnQgdW5pcXVlIGlkZW50aWZpZXJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrLCBjYWxsYmFja1xuICovXG52YXIgZGVwb3NpdCA9IGZ1bmN0aW9uIChmcm9tLCBhZGRyZXNzLCB2YWx1ZSwgY2xpZW50LCBjYWxsYmFjaykge1xuICAgIHZhciBhYmkgPSBbe1wiY29uc3RhbnRcIjpmYWxzZSxcImlucHV0c1wiOlt7XCJuYW1lXCI6XCJuYW1lXCIsXCJ0eXBlXCI6XCJieXRlczMyXCJ9XSxcIm5hbWVcIjpcImRlcG9zaXRcIixcIm91dHB1dHNcIjpbXSxcInR5cGVcIjpcImZ1bmN0aW9uXCJ9XTtcbiAgICByZXR1cm4gY29udHJhY3QoYWJpKS5hdChhZGRyZXNzKS5kZXBvc2l0KGNsaWVudCwge1xuICAgICAgICBmcm9tOiBmcm9tLFxuICAgICAgICB2YWx1ZTogdmFsdWVcbiAgICB9LCBjYWxsYmFjayk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IHRyYW5zZmVyO1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBAZmlsZSB3YXRjaGVzLmpzXG4gKiBAYXV0aG9yczpcbiAqICAgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE1XG4gKi9cblxudmFyIE1ldGhvZCA9IHJlcXVpcmUoJy4vbWV0aG9kJyk7XG5cbi8vLyBAcmV0dXJucyBhbiBhcnJheSBvZiBvYmplY3RzIGRlc2NyaWJpbmcgd2ViMy5ldGguZmlsdGVyIGFwaSBtZXRob2RzXG52YXIgZXRoID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBuZXdGaWx0ZXJDYWxsID0gZnVuY3Rpb24gKGFyZ3MpIHtcbiAgICAgICAgdmFyIHR5cGUgPSBhcmdzWzBdO1xuXG4gICAgICAgIHN3aXRjaCh0eXBlKSB7XG4gICAgICAgICAgICBjYXNlICdsYXRlc3QnOlxuICAgICAgICAgICAgICAgIGFyZ3MucG9wKCk7XG4gICAgICAgICAgICAgICAgdGhpcy5wYXJhbXMgPSAwO1xuICAgICAgICAgICAgICAgIHJldHVybiAnZXRoX25ld0Jsb2NrRmlsdGVyJztcbiAgICAgICAgICAgIGNhc2UgJ3BlbmRpbmcnOlxuICAgICAgICAgICAgICAgIGFyZ3MucG9wKCk7XG4gICAgICAgICAgICAgICAgdGhpcy5wYXJhbXMgPSAwO1xuICAgICAgICAgICAgICAgIHJldHVybiAnZXRoX25ld1BlbmRpbmdUcmFuc2FjdGlvbkZpbHRlcic7XG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIHJldHVybiAnZXRoX25ld0ZpbHRlcic7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdmFyIG5ld0ZpbHRlciA9IG5ldyBNZXRob2Qoe1xuICAgICAgICBuYW1lOiAnbmV3RmlsdGVyJyxcbiAgICAgICAgY2FsbDogbmV3RmlsdGVyQ2FsbCxcbiAgICAgICAgcGFyYW1zOiAxXG4gICAgfSk7XG5cbiAgICB2YXIgdW5pbnN0YWxsRmlsdGVyID0gbmV3IE1ldGhvZCh7XG4gICAgICAgIG5hbWU6ICd1bmluc3RhbGxGaWx0ZXInLFxuICAgICAgICBjYWxsOiAnZXRoX3VuaW5zdGFsbEZpbHRlcicsXG4gICAgICAgIHBhcmFtczogMVxuICAgIH0pO1xuXG4gICAgdmFyIGdldExvZ3MgPSBuZXcgTWV0aG9kKHtcbiAgICAgICAgbmFtZTogJ2dldExvZ3MnLFxuICAgICAgICBjYWxsOiAnZXRoX2dldEZpbHRlckxvZ3MnLFxuICAgICAgICBwYXJhbXM6IDFcbiAgICB9KTtcblxuICAgIHZhciBwb2xsID0gbmV3IE1ldGhvZCh7XG4gICAgICAgIG5hbWU6ICdwb2xsJyxcbiAgICAgICAgY2FsbDogJ2V0aF9nZXRGaWx0ZXJDaGFuZ2VzJyxcbiAgICAgICAgcGFyYW1zOiAxXG4gICAgfSk7XG5cbiAgICByZXR1cm4gW1xuICAgICAgICBuZXdGaWx0ZXIsXG4gICAgICAgIHVuaW5zdGFsbEZpbHRlcixcbiAgICAgICAgZ2V0TG9ncyxcbiAgICAgICAgcG9sbFxuICAgIF07XG59O1xuXG4vLy8gQHJldHVybnMgYW4gYXJyYXkgb2Ygb2JqZWN0cyBkZXNjcmliaW5nIHdlYjMuc2hoLndhdGNoIGFwaSBtZXRob2RzXG52YXIgc2hoID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBuZXdGaWx0ZXIgPSBuZXcgTWV0aG9kKHtcbiAgICAgICAgbmFtZTogJ25ld0ZpbHRlcicsXG4gICAgICAgIGNhbGw6ICdzaGhfbmV3RmlsdGVyJyxcbiAgICAgICAgcGFyYW1zOiAxXG4gICAgfSk7XG5cbiAgICB2YXIgdW5pbnN0YWxsRmlsdGVyID0gbmV3IE1ldGhvZCh7XG4gICAgICAgIG5hbWU6ICd1bmluc3RhbGxGaWx0ZXInLFxuICAgICAgICBjYWxsOiAnc2hoX3VuaW5zdGFsbEZpbHRlcicsXG4gICAgICAgIHBhcmFtczogMVxuICAgIH0pO1xuXG4gICAgdmFyIGdldExvZ3MgPSBuZXcgTWV0aG9kKHtcbiAgICAgICAgbmFtZTogJ2dldExvZ3MnLFxuICAgICAgICBjYWxsOiAnc2hoX2dldE1lc3NhZ2VzJyxcbiAgICAgICAgcGFyYW1zOiAxXG4gICAgfSk7XG5cbiAgICB2YXIgcG9sbCA9IG5ldyBNZXRob2Qoe1xuICAgICAgICBuYW1lOiAncG9sbCcsXG4gICAgICAgIGNhbGw6ICdzaGhfZ2V0RmlsdGVyQ2hhbmdlcycsXG4gICAgICAgIHBhcmFtczogMVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIFtcbiAgICAgICAgbmV3RmlsdGVyLFxuICAgICAgICB1bmluc3RhbGxGaWx0ZXIsXG4gICAgICAgIGdldExvZ3MsXG4gICAgICAgIHBvbGxcbiAgICBdO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgZXRoOiBldGgsXG4gICAgc2hoOiBzaGhcbn07XG5cbiIsbnVsbCwiOyhmdW5jdGlvbiAocm9vdCwgZmFjdG9yeSkge1xuXHRpZiAodHlwZW9mIGV4cG9ydHMgPT09IFwib2JqZWN0XCIpIHtcblx0XHQvLyBDb21tb25KU1xuXHRcdG1vZHVsZS5leHBvcnRzID0gZXhwb3J0cyA9IGZhY3RvcnkoKTtcblx0fVxuXHRlbHNlIGlmICh0eXBlb2YgZGVmaW5lID09PSBcImZ1bmN0aW9uXCIgJiYgZGVmaW5lLmFtZCkge1xuXHRcdC8vIEFNRFxuXHRcdGRlZmluZShbXSwgZmFjdG9yeSk7XG5cdH1cblx0ZWxzZSB7XG5cdFx0Ly8gR2xvYmFsIChicm93c2VyKVxuXHRcdHJvb3QuQ3J5cHRvSlMgPSBmYWN0b3J5KCk7XG5cdH1cbn0odGhpcywgZnVuY3Rpb24gKCkge1xuXG5cdC8qKlxuXHQgKiBDcnlwdG9KUyBjb3JlIGNvbXBvbmVudHMuXG5cdCAqL1xuXHR2YXIgQ3J5cHRvSlMgPSBDcnlwdG9KUyB8fCAoZnVuY3Rpb24gKE1hdGgsIHVuZGVmaW5lZCkge1xuXHQgICAgLyoqXG5cdCAgICAgKiBDcnlwdG9KUyBuYW1lc3BhY2UuXG5cdCAgICAgKi9cblx0ICAgIHZhciBDID0ge307XG5cblx0ICAgIC8qKlxuXHQgICAgICogTGlicmFyeSBuYW1lc3BhY2UuXG5cdCAgICAgKi9cblx0ICAgIHZhciBDX2xpYiA9IEMubGliID0ge307XG5cblx0ICAgIC8qKlxuXHQgICAgICogQmFzZSBvYmplY3QgZm9yIHByb3RvdHlwYWwgaW5oZXJpdGFuY2UuXG5cdCAgICAgKi9cblx0ICAgIHZhciBCYXNlID0gQ19saWIuQmFzZSA9IChmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgZnVuY3Rpb24gRigpIHt9XG5cblx0ICAgICAgICByZXR1cm4ge1xuXHQgICAgICAgICAgICAvKipcblx0ICAgICAgICAgICAgICogQ3JlYXRlcyBhIG5ldyBvYmplY3QgdGhhdCBpbmhlcml0cyBmcm9tIHRoaXMgb2JqZWN0LlxuXHQgICAgICAgICAgICAgKlxuXHQgICAgICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gb3ZlcnJpZGVzIFByb3BlcnRpZXMgdG8gY29weSBpbnRvIHRoZSBuZXcgb2JqZWN0LlxuXHQgICAgICAgICAgICAgKlxuXHQgICAgICAgICAgICAgKiBAcmV0dXJuIHtPYmplY3R9IFRoZSBuZXcgb2JqZWN0LlxuXHQgICAgICAgICAgICAgKlxuXHQgICAgICAgICAgICAgKiBAc3RhdGljXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqICAgICB2YXIgTXlUeXBlID0gQ3J5cHRvSlMubGliLkJhc2UuZXh0ZW5kKHtcblx0ICAgICAgICAgICAgICogICAgICAgICBmaWVsZDogJ3ZhbHVlJyxcblx0ICAgICAgICAgICAgICpcblx0ICAgICAgICAgICAgICogICAgICAgICBtZXRob2Q6IGZ1bmN0aW9uICgpIHtcblx0ICAgICAgICAgICAgICogICAgICAgICB9XG5cdCAgICAgICAgICAgICAqICAgICB9KTtcblx0ICAgICAgICAgICAgICovXG5cdCAgICAgICAgICAgIGV4dGVuZDogZnVuY3Rpb24gKG92ZXJyaWRlcykge1xuXHQgICAgICAgICAgICAgICAgLy8gU3Bhd25cblx0ICAgICAgICAgICAgICAgIEYucHJvdG90eXBlID0gdGhpcztcblx0ICAgICAgICAgICAgICAgIHZhciBzdWJ0eXBlID0gbmV3IEYoKTtcblxuXHQgICAgICAgICAgICAgICAgLy8gQXVnbWVudFxuXHQgICAgICAgICAgICAgICAgaWYgKG92ZXJyaWRlcykge1xuXHQgICAgICAgICAgICAgICAgICAgIHN1YnR5cGUubWl4SW4ob3ZlcnJpZGVzKTtcblx0ICAgICAgICAgICAgICAgIH1cblxuXHQgICAgICAgICAgICAgICAgLy8gQ3JlYXRlIGRlZmF1bHQgaW5pdGlhbGl6ZXJcblx0ICAgICAgICAgICAgICAgIGlmICghc3VidHlwZS5oYXNPd25Qcm9wZXJ0eSgnaW5pdCcpKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgc3VidHlwZS5pbml0ID0gZnVuY3Rpb24gKCkge1xuXHQgICAgICAgICAgICAgICAgICAgICAgICBzdWJ0eXBlLiRzdXBlci5pbml0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cdCAgICAgICAgICAgICAgICAgICAgfTtcblx0ICAgICAgICAgICAgICAgIH1cblxuXHQgICAgICAgICAgICAgICAgLy8gSW5pdGlhbGl6ZXIncyBwcm90b3R5cGUgaXMgdGhlIHN1YnR5cGUgb2JqZWN0XG5cdCAgICAgICAgICAgICAgICBzdWJ0eXBlLmluaXQucHJvdG90eXBlID0gc3VidHlwZTtcblxuXHQgICAgICAgICAgICAgICAgLy8gUmVmZXJlbmNlIHN1cGVydHlwZVxuXHQgICAgICAgICAgICAgICAgc3VidHlwZS4kc3VwZXIgPSB0aGlzO1xuXG5cdCAgICAgICAgICAgICAgICByZXR1cm4gc3VidHlwZTtcblx0ICAgICAgICAgICAgfSxcblxuXHQgICAgICAgICAgICAvKipcblx0ICAgICAgICAgICAgICogRXh0ZW5kcyB0aGlzIG9iamVjdCBhbmQgcnVucyB0aGUgaW5pdCBtZXRob2QuXG5cdCAgICAgICAgICAgICAqIEFyZ3VtZW50cyB0byBjcmVhdGUoKSB3aWxsIGJlIHBhc3NlZCB0byBpbml0KCkuXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqIEByZXR1cm4ge09iamVjdH0gVGhlIG5ldyBvYmplY3QuXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqIEBzdGF0aWNcblx0ICAgICAgICAgICAgICpcblx0ICAgICAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgICAgICpcblx0ICAgICAgICAgICAgICogICAgIHZhciBpbnN0YW5jZSA9IE15VHlwZS5jcmVhdGUoKTtcblx0ICAgICAgICAgICAgICovXG5cdCAgICAgICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gKCkge1xuXHQgICAgICAgICAgICAgICAgdmFyIGluc3RhbmNlID0gdGhpcy5leHRlbmQoKTtcblx0ICAgICAgICAgICAgICAgIGluc3RhbmNlLmluaXQuYXBwbHkoaW5zdGFuY2UsIGFyZ3VtZW50cyk7XG5cblx0ICAgICAgICAgICAgICAgIHJldHVybiBpbnN0YW5jZTtcblx0ICAgICAgICAgICAgfSxcblxuXHQgICAgICAgICAgICAvKipcblx0ICAgICAgICAgICAgICogSW5pdGlhbGl6ZXMgYSBuZXdseSBjcmVhdGVkIG9iamVjdC5cblx0ICAgICAgICAgICAgICogT3ZlcnJpZGUgdGhpcyBtZXRob2QgdG8gYWRkIHNvbWUgbG9naWMgd2hlbiB5b3VyIG9iamVjdHMgYXJlIGNyZWF0ZWQuXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqICAgICB2YXIgTXlUeXBlID0gQ3J5cHRvSlMubGliLkJhc2UuZXh0ZW5kKHtcblx0ICAgICAgICAgICAgICogICAgICAgICBpbml0OiBmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgICAgICAqICAgICAgICAgICAgIC8vIC4uLlxuXHQgICAgICAgICAgICAgKiAgICAgICAgIH1cblx0ICAgICAgICAgICAgICogICAgIH0pO1xuXHQgICAgICAgICAgICAgKi9cblx0ICAgICAgICAgICAgaW5pdDogZnVuY3Rpb24gKCkge1xuXHQgICAgICAgICAgICB9LFxuXG5cdCAgICAgICAgICAgIC8qKlxuXHQgICAgICAgICAgICAgKiBDb3BpZXMgcHJvcGVydGllcyBpbnRvIHRoaXMgb2JqZWN0LlxuXHQgICAgICAgICAgICAgKlxuXHQgICAgICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gcHJvcGVydGllcyBUaGUgcHJvcGVydGllcyB0byBtaXggaW4uXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqICAgICBNeVR5cGUubWl4SW4oe1xuXHQgICAgICAgICAgICAgKiAgICAgICAgIGZpZWxkOiAndmFsdWUnXG5cdCAgICAgICAgICAgICAqICAgICB9KTtcblx0ICAgICAgICAgICAgICovXG5cdCAgICAgICAgICAgIG1peEluOiBmdW5jdGlvbiAocHJvcGVydGllcykge1xuXHQgICAgICAgICAgICAgICAgZm9yICh2YXIgcHJvcGVydHlOYW1lIGluIHByb3BlcnRpZXMpIHtcblx0ICAgICAgICAgICAgICAgICAgICBpZiAocHJvcGVydGllcy5oYXNPd25Qcm9wZXJ0eShwcm9wZXJ0eU5hbWUpKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIHRoaXNbcHJvcGVydHlOYW1lXSA9IHByb3BlcnRpZXNbcHJvcGVydHlOYW1lXTtcblx0ICAgICAgICAgICAgICAgICAgICB9XG5cdCAgICAgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgICAgIC8vIElFIHdvbid0IGNvcHkgdG9TdHJpbmcgdXNpbmcgdGhlIGxvb3AgYWJvdmVcblx0ICAgICAgICAgICAgICAgIGlmIChwcm9wZXJ0aWVzLmhhc093blByb3BlcnR5KCd0b1N0cmluZycpKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgdGhpcy50b1N0cmluZyA9IHByb3BlcnRpZXMudG9TdHJpbmc7XG5cdCAgICAgICAgICAgICAgICB9XG5cdCAgICAgICAgICAgIH0sXG5cblx0ICAgICAgICAgICAgLyoqXG5cdCAgICAgICAgICAgICAqIENyZWF0ZXMgYSBjb3B5IG9mIHRoaXMgb2JqZWN0LlxuXHQgICAgICAgICAgICAgKlxuXHQgICAgICAgICAgICAgKiBAcmV0dXJuIHtPYmplY3R9IFRoZSBjbG9uZS5cblx0ICAgICAgICAgICAgICpcblx0ICAgICAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgICAgICpcblx0ICAgICAgICAgICAgICogICAgIHZhciBjbG9uZSA9IGluc3RhbmNlLmNsb25lKCk7XG5cdCAgICAgICAgICAgICAqL1xuXHQgICAgICAgICAgICBjbG9uZTogZnVuY3Rpb24gKCkge1xuXHQgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuaW5pdC5wcm90b3R5cGUuZXh0ZW5kKHRoaXMpO1xuXHQgICAgICAgICAgICB9XG5cdCAgICAgICAgfTtcblx0ICAgIH0oKSk7XG5cblx0ICAgIC8qKlxuXHQgICAgICogQW4gYXJyYXkgb2YgMzItYml0IHdvcmRzLlxuXHQgICAgICpcblx0ICAgICAqIEBwcm9wZXJ0eSB7QXJyYXl9IHdvcmRzIFRoZSBhcnJheSBvZiAzMi1iaXQgd29yZHMuXG5cdCAgICAgKiBAcHJvcGVydHkge251bWJlcn0gc2lnQnl0ZXMgVGhlIG51bWJlciBvZiBzaWduaWZpY2FudCBieXRlcyBpbiB0aGlzIHdvcmQgYXJyYXkuXG5cdCAgICAgKi9cblx0ICAgIHZhciBXb3JkQXJyYXkgPSBDX2xpYi5Xb3JkQXJyYXkgPSBCYXNlLmV4dGVuZCh7XG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogSW5pdGlhbGl6ZXMgYSBuZXdseSBjcmVhdGVkIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge0FycmF5fSB3b3JkcyAoT3B0aW9uYWwpIEFuIGFycmF5IG9mIDMyLWJpdCB3b3Jkcy5cblx0ICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gc2lnQnl0ZXMgKE9wdGlvbmFsKSBUaGUgbnVtYmVyIG9mIHNpZ25pZmljYW50IGJ5dGVzIGluIHRoZSB3b3Jkcy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIHdvcmRBcnJheSA9IENyeXB0b0pTLmxpYi5Xb3JkQXJyYXkuY3JlYXRlKCk7XG5cdCAgICAgICAgICogICAgIHZhciB3b3JkQXJyYXkgPSBDcnlwdG9KUy5saWIuV29yZEFycmF5LmNyZWF0ZShbMHgwMDAxMDIwMywgMHgwNDA1MDYwN10pO1xuXHQgICAgICAgICAqICAgICB2YXIgd29yZEFycmF5ID0gQ3J5cHRvSlMubGliLldvcmRBcnJheS5jcmVhdGUoWzB4MDAwMTAyMDMsIDB4MDQwNTA2MDddLCA2KTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICBpbml0OiBmdW5jdGlvbiAod29yZHMsIHNpZ0J5dGVzKSB7XG5cdCAgICAgICAgICAgIHdvcmRzID0gdGhpcy53b3JkcyA9IHdvcmRzIHx8IFtdO1xuXG5cdCAgICAgICAgICAgIGlmIChzaWdCeXRlcyAhPSB1bmRlZmluZWQpIHtcblx0ICAgICAgICAgICAgICAgIHRoaXMuc2lnQnl0ZXMgPSBzaWdCeXRlcztcblx0ICAgICAgICAgICAgfSBlbHNlIHtcblx0ICAgICAgICAgICAgICAgIHRoaXMuc2lnQnl0ZXMgPSB3b3Jkcy5sZW5ndGggKiA0O1xuXHQgICAgICAgICAgICB9XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIENvbnZlcnRzIHRoaXMgd29yZCBhcnJheSB0byBhIHN0cmluZy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7RW5jb2Rlcn0gZW5jb2RlciAoT3B0aW9uYWwpIFRoZSBlbmNvZGluZyBzdHJhdGVneSB0byB1c2UuIERlZmF1bHQ6IENyeXB0b0pTLmVuYy5IZXhcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge3N0cmluZ30gVGhlIHN0cmluZ2lmaWVkIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciBzdHJpbmcgPSB3b3JkQXJyYXkgKyAnJztcblx0ICAgICAgICAgKiAgICAgdmFyIHN0cmluZyA9IHdvcmRBcnJheS50b1N0cmluZygpO1xuXHQgICAgICAgICAqICAgICB2YXIgc3RyaW5nID0gd29yZEFycmF5LnRvU3RyaW5nKENyeXB0b0pTLmVuYy5VdGY4KTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICB0b1N0cmluZzogZnVuY3Rpb24gKGVuY29kZXIpIHtcblx0ICAgICAgICAgICAgcmV0dXJuIChlbmNvZGVyIHx8IEhleCkuc3RyaW5naWZ5KHRoaXMpO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDb25jYXRlbmF0ZXMgYSB3b3JkIGFycmF5IHRvIHRoaXMgd29yZCBhcnJheS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7V29yZEFycmF5fSB3b3JkQXJyYXkgVGhlIHdvcmQgYXJyYXkgdG8gYXBwZW5kLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7V29yZEFycmF5fSBUaGlzIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHdvcmRBcnJheTEuY29uY2F0KHdvcmRBcnJheTIpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIGNvbmNhdDogZnVuY3Rpb24gKHdvcmRBcnJheSkge1xuXHQgICAgICAgICAgICAvLyBTaG9ydGN1dHNcblx0ICAgICAgICAgICAgdmFyIHRoaXNXb3JkcyA9IHRoaXMud29yZHM7XG5cdCAgICAgICAgICAgIHZhciB0aGF0V29yZHMgPSB3b3JkQXJyYXkud29yZHM7XG5cdCAgICAgICAgICAgIHZhciB0aGlzU2lnQnl0ZXMgPSB0aGlzLnNpZ0J5dGVzO1xuXHQgICAgICAgICAgICB2YXIgdGhhdFNpZ0J5dGVzID0gd29yZEFycmF5LnNpZ0J5dGVzO1xuXG5cdCAgICAgICAgICAgIC8vIENsYW1wIGV4Y2VzcyBiaXRzXG5cdCAgICAgICAgICAgIHRoaXMuY2xhbXAoKTtcblxuXHQgICAgICAgICAgICAvLyBDb25jYXRcblx0ICAgICAgICAgICAgaWYgKHRoaXNTaWdCeXRlcyAlIDQpIHtcblx0ICAgICAgICAgICAgICAgIC8vIENvcHkgb25lIGJ5dGUgYXQgYSB0aW1lXG5cdCAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoYXRTaWdCeXRlczsgaSsrKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgdmFyIHRoYXRCeXRlID0gKHRoYXRXb3Jkc1tpID4+PiAyXSA+Pj4gKDI0IC0gKGkgJSA0KSAqIDgpKSAmIDB4ZmY7XG5cdCAgICAgICAgICAgICAgICAgICAgdGhpc1dvcmRzWyh0aGlzU2lnQnl0ZXMgKyBpKSA+Pj4gMl0gfD0gdGhhdEJ5dGUgPDwgKDI0IC0gKCh0aGlzU2lnQnl0ZXMgKyBpKSAlIDQpICogOCk7XG5cdCAgICAgICAgICAgICAgICB9XG5cdCAgICAgICAgICAgIH0gZWxzZSB7XG5cdCAgICAgICAgICAgICAgICAvLyBDb3B5IG9uZSB3b3JkIGF0IGEgdGltZVxuXHQgICAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGF0U2lnQnl0ZXM7IGkgKz0gNCkge1xuXHQgICAgICAgICAgICAgICAgICAgIHRoaXNXb3Jkc1sodGhpc1NpZ0J5dGVzICsgaSkgPj4+IDJdID0gdGhhdFdvcmRzW2kgPj4+IDJdO1xuXHQgICAgICAgICAgICAgICAgfVxuXHQgICAgICAgICAgICB9XG5cdCAgICAgICAgICAgIHRoaXMuc2lnQnl0ZXMgKz0gdGhhdFNpZ0J5dGVzO1xuXG5cdCAgICAgICAgICAgIC8vIENoYWluYWJsZVxuXHQgICAgICAgICAgICByZXR1cm4gdGhpcztcblx0ICAgICAgICB9LFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogUmVtb3ZlcyBpbnNpZ25pZmljYW50IGJpdHMuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHdvcmRBcnJheS5jbGFtcCgpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIGNsYW1wOiBmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgICAgIC8vIFNob3J0Y3V0c1xuXHQgICAgICAgICAgICB2YXIgd29yZHMgPSB0aGlzLndvcmRzO1xuXHQgICAgICAgICAgICB2YXIgc2lnQnl0ZXMgPSB0aGlzLnNpZ0J5dGVzO1xuXG5cdCAgICAgICAgICAgIC8vIENsYW1wXG5cdCAgICAgICAgICAgIHdvcmRzW3NpZ0J5dGVzID4+PiAyXSAmPSAweGZmZmZmZmZmIDw8ICgzMiAtIChzaWdCeXRlcyAlIDQpICogOCk7XG5cdCAgICAgICAgICAgIHdvcmRzLmxlbmd0aCA9IE1hdGguY2VpbChzaWdCeXRlcyAvIDQpO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDcmVhdGVzIGEgY29weSBvZiB0aGlzIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtXb3JkQXJyYXl9IFRoZSBjbG9uZS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIGNsb25lID0gd29yZEFycmF5LmNsb25lKCk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgY2xvbmU6IGZ1bmN0aW9uICgpIHtcblx0ICAgICAgICAgICAgdmFyIGNsb25lID0gQmFzZS5jbG9uZS5jYWxsKHRoaXMpO1xuXHQgICAgICAgICAgICBjbG9uZS53b3JkcyA9IHRoaXMud29yZHMuc2xpY2UoMCk7XG5cblx0ICAgICAgICAgICAgcmV0dXJuIGNsb25lO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDcmVhdGVzIGEgd29yZCBhcnJheSBmaWxsZWQgd2l0aCByYW5kb20gYnl0ZXMuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gbkJ5dGVzIFRoZSBudW1iZXIgb2YgcmFuZG9tIGJ5dGVzIHRvIGdlbmVyYXRlLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7V29yZEFycmF5fSBUaGUgcmFuZG9tIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAc3RhdGljXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciB3b3JkQXJyYXkgPSBDcnlwdG9KUy5saWIuV29yZEFycmF5LnJhbmRvbSgxNik7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgcmFuZG9tOiBmdW5jdGlvbiAobkJ5dGVzKSB7XG5cdCAgICAgICAgICAgIHZhciB3b3JkcyA9IFtdO1xuXG5cdCAgICAgICAgICAgIHZhciByID0gKGZ1bmN0aW9uIChtX3cpIHtcblx0ICAgICAgICAgICAgICAgIHZhciBtX3cgPSBtX3c7XG5cdCAgICAgICAgICAgICAgICB2YXIgbV96ID0gMHgzYWRlNjhiMTtcblx0ICAgICAgICAgICAgICAgIHZhciBtYXNrID0gMHhmZmZmZmZmZjtcblxuXHQgICAgICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uICgpIHtcblx0ICAgICAgICAgICAgICAgICAgICBtX3ogPSAoMHg5MDY5ICogKG1feiAmIDB4RkZGRikgKyAobV96ID4+IDB4MTApKSAmIG1hc2s7XG5cdCAgICAgICAgICAgICAgICAgICAgbV93ID0gKDB4NDY1MCAqIChtX3cgJiAweEZGRkYpICsgKG1fdyA+PiAweDEwKSkgJiBtYXNrO1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciByZXN1bHQgPSAoKG1feiA8PCAweDEwKSArIG1fdykgJiBtYXNrO1xuXHQgICAgICAgICAgICAgICAgICAgIHJlc3VsdCAvPSAweDEwMDAwMDAwMDtcblx0ICAgICAgICAgICAgICAgICAgICByZXN1bHQgKz0gMC41O1xuXHQgICAgICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQgKiAoTWF0aC5yYW5kb20oKSA+IC41ID8gMSA6IC0xKTtcblx0ICAgICAgICAgICAgICAgIH1cblx0ICAgICAgICAgICAgfSk7XG5cblx0ICAgICAgICAgICAgZm9yICh2YXIgaSA9IDAsIHJjYWNoZTsgaSA8IG5CeXRlczsgaSArPSA0KSB7XG5cdCAgICAgICAgICAgICAgICB2YXIgX3IgPSByKChyY2FjaGUgfHwgTWF0aC5yYW5kb20oKSkgKiAweDEwMDAwMDAwMCk7XG5cblx0ICAgICAgICAgICAgICAgIHJjYWNoZSA9IF9yKCkgKiAweDNhZGU2N2I3O1xuXHQgICAgICAgICAgICAgICAgd29yZHMucHVzaCgoX3IoKSAqIDB4MTAwMDAwMDAwKSB8IDApO1xuXHQgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgcmV0dXJuIG5ldyBXb3JkQXJyYXkuaW5pdCh3b3JkcywgbkJ5dGVzKTtcblx0ICAgICAgICB9XG5cdCAgICB9KTtcblxuXHQgICAgLyoqXG5cdCAgICAgKiBFbmNvZGVyIG5hbWVzcGFjZS5cblx0ICAgICAqL1xuXHQgICAgdmFyIENfZW5jID0gQy5lbmMgPSB7fTtcblxuXHQgICAgLyoqXG5cdCAgICAgKiBIZXggZW5jb2Rpbmcgc3RyYXRlZ3kuXG5cdCAgICAgKi9cblx0ICAgIHZhciBIZXggPSBDX2VuYy5IZXggPSB7XG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogQ29udmVydHMgYSB3b3JkIGFycmF5IHRvIGEgaGV4IHN0cmluZy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7V29yZEFycmF5fSB3b3JkQXJyYXkgVGhlIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBoZXggc3RyaW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHN0YXRpY1xuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgaGV4U3RyaW5nID0gQ3J5cHRvSlMuZW5jLkhleC5zdHJpbmdpZnkod29yZEFycmF5KTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICBzdHJpbmdpZnk6IGZ1bmN0aW9uICh3b3JkQXJyYXkpIHtcblx0ICAgICAgICAgICAgLy8gU2hvcnRjdXRzXG5cdCAgICAgICAgICAgIHZhciB3b3JkcyA9IHdvcmRBcnJheS53b3Jkcztcblx0ICAgICAgICAgICAgdmFyIHNpZ0J5dGVzID0gd29yZEFycmF5LnNpZ0J5dGVzO1xuXG5cdCAgICAgICAgICAgIC8vIENvbnZlcnRcblx0ICAgICAgICAgICAgdmFyIGhleENoYXJzID0gW107XG5cdCAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2lnQnl0ZXM7IGkrKykge1xuXHQgICAgICAgICAgICAgICAgdmFyIGJpdGUgPSAod29yZHNbaSA+Pj4gMl0gPj4+ICgyNCAtIChpICUgNCkgKiA4KSkgJiAweGZmO1xuXHQgICAgICAgICAgICAgICAgaGV4Q2hhcnMucHVzaCgoYml0ZSA+Pj4gNCkudG9TdHJpbmcoMTYpKTtcblx0ICAgICAgICAgICAgICAgIGhleENoYXJzLnB1c2goKGJpdGUgJiAweDBmKS50b1N0cmluZygxNikpO1xuXHQgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgcmV0dXJuIGhleENoYXJzLmpvaW4oJycpO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDb252ZXJ0cyBhIGhleCBzdHJpbmcgdG8gYSB3b3JkIGFycmF5LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGhleFN0ciBUaGUgaGV4IHN0cmluZy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge1dvcmRBcnJheX0gVGhlIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAc3RhdGljXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciB3b3JkQXJyYXkgPSBDcnlwdG9KUy5lbmMuSGV4LnBhcnNlKGhleFN0cmluZyk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgcGFyc2U6IGZ1bmN0aW9uIChoZXhTdHIpIHtcblx0ICAgICAgICAgICAgLy8gU2hvcnRjdXRcblx0ICAgICAgICAgICAgdmFyIGhleFN0ckxlbmd0aCA9IGhleFN0ci5sZW5ndGg7XG5cblx0ICAgICAgICAgICAgLy8gQ29udmVydFxuXHQgICAgICAgICAgICB2YXIgd29yZHMgPSBbXTtcblx0ICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBoZXhTdHJMZW5ndGg7IGkgKz0gMikge1xuXHQgICAgICAgICAgICAgICAgd29yZHNbaSA+Pj4gM10gfD0gcGFyc2VJbnQoaGV4U3RyLnN1YnN0cihpLCAyKSwgMTYpIDw8ICgyNCAtIChpICUgOCkgKiA0KTtcblx0ICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgIHJldHVybiBuZXcgV29yZEFycmF5LmluaXQod29yZHMsIGhleFN0ckxlbmd0aCAvIDIpO1xuXHQgICAgICAgIH1cblx0ICAgIH07XG5cblx0ICAgIC8qKlxuXHQgICAgICogTGF0aW4xIGVuY29kaW5nIHN0cmF0ZWd5LlxuXHQgICAgICovXG5cdCAgICB2YXIgTGF0aW4xID0gQ19lbmMuTGF0aW4xID0ge1xuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIENvbnZlcnRzIGEgd29yZCBhcnJheSB0byBhIExhdGluMSBzdHJpbmcuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge1dvcmRBcnJheX0gd29yZEFycmF5IFRoZSB3b3JkIGFycmF5LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7c3RyaW5nfSBUaGUgTGF0aW4xIHN0cmluZy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBzdGF0aWNcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIGxhdGluMVN0cmluZyA9IENyeXB0b0pTLmVuYy5MYXRpbjEuc3RyaW5naWZ5KHdvcmRBcnJheSk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgc3RyaW5naWZ5OiBmdW5jdGlvbiAod29yZEFycmF5KSB7XG5cdCAgICAgICAgICAgIC8vIFNob3J0Y3V0c1xuXHQgICAgICAgICAgICB2YXIgd29yZHMgPSB3b3JkQXJyYXkud29yZHM7XG5cdCAgICAgICAgICAgIHZhciBzaWdCeXRlcyA9IHdvcmRBcnJheS5zaWdCeXRlcztcblxuXHQgICAgICAgICAgICAvLyBDb252ZXJ0XG5cdCAgICAgICAgICAgIHZhciBsYXRpbjFDaGFycyA9IFtdO1xuXHQgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNpZ0J5dGVzOyBpKyspIHtcblx0ICAgICAgICAgICAgICAgIHZhciBiaXRlID0gKHdvcmRzW2kgPj4+IDJdID4+PiAoMjQgLSAoaSAlIDQpICogOCkpICYgMHhmZjtcblx0ICAgICAgICAgICAgICAgIGxhdGluMUNoYXJzLnB1c2goU3RyaW5nLmZyb21DaGFyQ29kZShiaXRlKSk7XG5cdCAgICAgICAgICAgIH1cblxuXHQgICAgICAgICAgICByZXR1cm4gbGF0aW4xQ2hhcnMuam9pbignJyk7XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIENvbnZlcnRzIGEgTGF0aW4xIHN0cmluZyB0byBhIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gbGF0aW4xU3RyIFRoZSBMYXRpbjEgc3RyaW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7V29yZEFycmF5fSBUaGUgd29yZCBhcnJheS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBzdGF0aWNcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIHdvcmRBcnJheSA9IENyeXB0b0pTLmVuYy5MYXRpbjEucGFyc2UobGF0aW4xU3RyaW5nKTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICBwYXJzZTogZnVuY3Rpb24gKGxhdGluMVN0cikge1xuXHQgICAgICAgICAgICAvLyBTaG9ydGN1dFxuXHQgICAgICAgICAgICB2YXIgbGF0aW4xU3RyTGVuZ3RoID0gbGF0aW4xU3RyLmxlbmd0aDtcblxuXHQgICAgICAgICAgICAvLyBDb252ZXJ0XG5cdCAgICAgICAgICAgIHZhciB3b3JkcyA9IFtdO1xuXHQgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxhdGluMVN0ckxlbmd0aDsgaSsrKSB7XG5cdCAgICAgICAgICAgICAgICB3b3Jkc1tpID4+PiAyXSB8PSAobGF0aW4xU3RyLmNoYXJDb2RlQXQoaSkgJiAweGZmKSA8PCAoMjQgLSAoaSAlIDQpICogOCk7XG5cdCAgICAgICAgICAgIH1cblxuXHQgICAgICAgICAgICByZXR1cm4gbmV3IFdvcmRBcnJheS5pbml0KHdvcmRzLCBsYXRpbjFTdHJMZW5ndGgpO1xuXHQgICAgICAgIH1cblx0ICAgIH07XG5cblx0ICAgIC8qKlxuXHQgICAgICogVVRGLTggZW5jb2Rpbmcgc3RyYXRlZ3kuXG5cdCAgICAgKi9cblx0ICAgIHZhciBVdGY4ID0gQ19lbmMuVXRmOCA9IHtcblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDb252ZXJ0cyBhIHdvcmQgYXJyYXkgdG8gYSBVVEYtOCBzdHJpbmcuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge1dvcmRBcnJheX0gd29yZEFycmF5IFRoZSB3b3JkIGFycmF5LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7c3RyaW5nfSBUaGUgVVRGLTggc3RyaW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHN0YXRpY1xuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgdXRmOFN0cmluZyA9IENyeXB0b0pTLmVuYy5VdGY4LnN0cmluZ2lmeSh3b3JkQXJyYXkpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIHN0cmluZ2lmeTogZnVuY3Rpb24gKHdvcmRBcnJheSkge1xuXHQgICAgICAgICAgICB0cnkge1xuXHQgICAgICAgICAgICAgICAgcmV0dXJuIGRlY29kZVVSSUNvbXBvbmVudChlc2NhcGUoTGF0aW4xLnN0cmluZ2lmeSh3b3JkQXJyYXkpKSk7XG5cdCAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcblx0ICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignTWFsZm9ybWVkIFVURi04IGRhdGEnKTtcblx0ICAgICAgICAgICAgfVxuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDb252ZXJ0cyBhIFVURi04IHN0cmluZyB0byBhIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gdXRmOFN0ciBUaGUgVVRGLTggc3RyaW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7V29yZEFycmF5fSBUaGUgd29yZCBhcnJheS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBzdGF0aWNcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIHdvcmRBcnJheSA9IENyeXB0b0pTLmVuYy5VdGY4LnBhcnNlKHV0ZjhTdHJpbmcpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIHBhcnNlOiBmdW5jdGlvbiAodXRmOFN0cikge1xuXHQgICAgICAgICAgICByZXR1cm4gTGF0aW4xLnBhcnNlKHVuZXNjYXBlKGVuY29kZVVSSUNvbXBvbmVudCh1dGY4U3RyKSkpO1xuXHQgICAgICAgIH1cblx0ICAgIH07XG5cblx0ICAgIC8qKlxuXHQgICAgICogQWJzdHJhY3QgYnVmZmVyZWQgYmxvY2sgYWxnb3JpdGhtIHRlbXBsYXRlLlxuXHQgICAgICpcblx0ICAgICAqIFRoZSBwcm9wZXJ0eSBibG9ja1NpemUgbXVzdCBiZSBpbXBsZW1lbnRlZCBpbiBhIGNvbmNyZXRlIHN1YnR5cGUuXG5cdCAgICAgKlxuXHQgICAgICogQHByb3BlcnR5IHtudW1iZXJ9IF9taW5CdWZmZXJTaXplIFRoZSBudW1iZXIgb2YgYmxvY2tzIHRoYXQgc2hvdWxkIGJlIGtlcHQgdW5wcm9jZXNzZWQgaW4gdGhlIGJ1ZmZlci4gRGVmYXVsdDogMFxuXHQgICAgICovXG5cdCAgICB2YXIgQnVmZmVyZWRCbG9ja0FsZ29yaXRobSA9IENfbGliLkJ1ZmZlcmVkQmxvY2tBbGdvcml0aG0gPSBCYXNlLmV4dGVuZCh7XG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogUmVzZXRzIHRoaXMgYmxvY2sgYWxnb3JpdGhtJ3MgZGF0YSBidWZmZXIgdG8gaXRzIGluaXRpYWwgc3RhdGUuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIGJ1ZmZlcmVkQmxvY2tBbGdvcml0aG0ucmVzZXQoKTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICByZXNldDogZnVuY3Rpb24gKCkge1xuXHQgICAgICAgICAgICAvLyBJbml0aWFsIHZhbHVlc1xuXHQgICAgICAgICAgICB0aGlzLl9kYXRhID0gbmV3IFdvcmRBcnJheS5pbml0KCk7XG5cdCAgICAgICAgICAgIHRoaXMuX25EYXRhQnl0ZXMgPSAwO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBBZGRzIG5ldyBkYXRhIHRvIHRoaXMgYmxvY2sgYWxnb3JpdGhtJ3MgYnVmZmVyLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtXb3JkQXJyYXl8c3RyaW5nfSBkYXRhIFRoZSBkYXRhIHRvIGFwcGVuZC4gU3RyaW5ncyBhcmUgY29udmVydGVkIHRvIGEgV29yZEFycmF5IHVzaW5nIFVURi04LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICBidWZmZXJlZEJsb2NrQWxnb3JpdGhtLl9hcHBlbmQoJ2RhdGEnKTtcblx0ICAgICAgICAgKiAgICAgYnVmZmVyZWRCbG9ja0FsZ29yaXRobS5fYXBwZW5kKHdvcmRBcnJheSk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgX2FwcGVuZDogZnVuY3Rpb24gKGRhdGEpIHtcblx0ICAgICAgICAgICAgLy8gQ29udmVydCBzdHJpbmcgdG8gV29yZEFycmF5LCBlbHNlIGFzc3VtZSBXb3JkQXJyYXkgYWxyZWFkeVxuXHQgICAgICAgICAgICBpZiAodHlwZW9mIGRhdGEgPT0gJ3N0cmluZycpIHtcblx0ICAgICAgICAgICAgICAgIGRhdGEgPSBVdGY4LnBhcnNlKGRhdGEpO1xuXHQgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgLy8gQXBwZW5kXG5cdCAgICAgICAgICAgIHRoaXMuX2RhdGEuY29uY2F0KGRhdGEpO1xuXHQgICAgICAgICAgICB0aGlzLl9uRGF0YUJ5dGVzICs9IGRhdGEuc2lnQnl0ZXM7XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIFByb2Nlc3NlcyBhdmFpbGFibGUgZGF0YSBibG9ja3MuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBUaGlzIG1ldGhvZCBpbnZva2VzIF9kb1Byb2Nlc3NCbG9jayhvZmZzZXQpLCB3aGljaCBtdXN0IGJlIGltcGxlbWVudGVkIGJ5IGEgY29uY3JldGUgc3VidHlwZS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gZG9GbHVzaCBXaGV0aGVyIGFsbCBibG9ja3MgYW5kIHBhcnRpYWwgYmxvY2tzIHNob3VsZCBiZSBwcm9jZXNzZWQuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtXb3JkQXJyYXl9IFRoZSBwcm9jZXNzZWQgZGF0YS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIHByb2Nlc3NlZERhdGEgPSBidWZmZXJlZEJsb2NrQWxnb3JpdGhtLl9wcm9jZXNzKCk7XG5cdCAgICAgICAgICogICAgIHZhciBwcm9jZXNzZWREYXRhID0gYnVmZmVyZWRCbG9ja0FsZ29yaXRobS5fcHJvY2VzcyghISdmbHVzaCcpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIF9wcm9jZXNzOiBmdW5jdGlvbiAoZG9GbHVzaCkge1xuXHQgICAgICAgICAgICAvLyBTaG9ydGN1dHNcblx0ICAgICAgICAgICAgdmFyIGRhdGEgPSB0aGlzLl9kYXRhO1xuXHQgICAgICAgICAgICB2YXIgZGF0YVdvcmRzID0gZGF0YS53b3Jkcztcblx0ICAgICAgICAgICAgdmFyIGRhdGFTaWdCeXRlcyA9IGRhdGEuc2lnQnl0ZXM7XG5cdCAgICAgICAgICAgIHZhciBibG9ja1NpemUgPSB0aGlzLmJsb2NrU2l6ZTtcblx0ICAgICAgICAgICAgdmFyIGJsb2NrU2l6ZUJ5dGVzID0gYmxvY2tTaXplICogNDtcblxuXHQgICAgICAgICAgICAvLyBDb3VudCBibG9ja3MgcmVhZHlcblx0ICAgICAgICAgICAgdmFyIG5CbG9ja3NSZWFkeSA9IGRhdGFTaWdCeXRlcyAvIGJsb2NrU2l6ZUJ5dGVzO1xuXHQgICAgICAgICAgICBpZiAoZG9GbHVzaCkge1xuXHQgICAgICAgICAgICAgICAgLy8gUm91bmQgdXAgdG8gaW5jbHVkZSBwYXJ0aWFsIGJsb2Nrc1xuXHQgICAgICAgICAgICAgICAgbkJsb2Nrc1JlYWR5ID0gTWF0aC5jZWlsKG5CbG9ja3NSZWFkeSk7XG5cdCAgICAgICAgICAgIH0gZWxzZSB7XG5cdCAgICAgICAgICAgICAgICAvLyBSb3VuZCBkb3duIHRvIGluY2x1ZGUgb25seSBmdWxsIGJsb2Nrcyxcblx0ICAgICAgICAgICAgICAgIC8vIGxlc3MgdGhlIG51bWJlciBvZiBibG9ja3MgdGhhdCBtdXN0IHJlbWFpbiBpbiB0aGUgYnVmZmVyXG5cdCAgICAgICAgICAgICAgICBuQmxvY2tzUmVhZHkgPSBNYXRoLm1heCgobkJsb2Nrc1JlYWR5IHwgMCkgLSB0aGlzLl9taW5CdWZmZXJTaXplLCAwKTtcblx0ICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgIC8vIENvdW50IHdvcmRzIHJlYWR5XG5cdCAgICAgICAgICAgIHZhciBuV29yZHNSZWFkeSA9IG5CbG9ja3NSZWFkeSAqIGJsb2NrU2l6ZTtcblxuXHQgICAgICAgICAgICAvLyBDb3VudCBieXRlcyByZWFkeVxuXHQgICAgICAgICAgICB2YXIgbkJ5dGVzUmVhZHkgPSBNYXRoLm1pbihuV29yZHNSZWFkeSAqIDQsIGRhdGFTaWdCeXRlcyk7XG5cblx0ICAgICAgICAgICAgLy8gUHJvY2VzcyBibG9ja3Ncblx0ICAgICAgICAgICAgaWYgKG5Xb3Jkc1JlYWR5KSB7XG5cdCAgICAgICAgICAgICAgICBmb3IgKHZhciBvZmZzZXQgPSAwOyBvZmZzZXQgPCBuV29yZHNSZWFkeTsgb2Zmc2V0ICs9IGJsb2NrU2l6ZSkge1xuXHQgICAgICAgICAgICAgICAgICAgIC8vIFBlcmZvcm0gY29uY3JldGUtYWxnb3JpdGhtIGxvZ2ljXG5cdCAgICAgICAgICAgICAgICAgICAgdGhpcy5fZG9Qcm9jZXNzQmxvY2soZGF0YVdvcmRzLCBvZmZzZXQpO1xuXHQgICAgICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgICAgICAvLyBSZW1vdmUgcHJvY2Vzc2VkIHdvcmRzXG5cdCAgICAgICAgICAgICAgICB2YXIgcHJvY2Vzc2VkV29yZHMgPSBkYXRhV29yZHMuc3BsaWNlKDAsIG5Xb3Jkc1JlYWR5KTtcblx0ICAgICAgICAgICAgICAgIGRhdGEuc2lnQnl0ZXMgLT0gbkJ5dGVzUmVhZHk7XG5cdCAgICAgICAgICAgIH1cblxuXHQgICAgICAgICAgICAvLyBSZXR1cm4gcHJvY2Vzc2VkIHdvcmRzXG5cdCAgICAgICAgICAgIHJldHVybiBuZXcgV29yZEFycmF5LmluaXQocHJvY2Vzc2VkV29yZHMsIG5CeXRlc1JlYWR5KTtcblx0ICAgICAgICB9LFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogQ3JlYXRlcyBhIGNvcHkgb2YgdGhpcyBvYmplY3QuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtPYmplY3R9IFRoZSBjbG9uZS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIGNsb25lID0gYnVmZmVyZWRCbG9ja0FsZ29yaXRobS5jbG9uZSgpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIGNsb25lOiBmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgICAgIHZhciBjbG9uZSA9IEJhc2UuY2xvbmUuY2FsbCh0aGlzKTtcblx0ICAgICAgICAgICAgY2xvbmUuX2RhdGEgPSB0aGlzLl9kYXRhLmNsb25lKCk7XG5cblx0ICAgICAgICAgICAgcmV0dXJuIGNsb25lO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICBfbWluQnVmZmVyU2l6ZTogMFxuXHQgICAgfSk7XG5cblx0ICAgIC8qKlxuXHQgICAgICogQWJzdHJhY3QgaGFzaGVyIHRlbXBsYXRlLlxuXHQgICAgICpcblx0ICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBibG9ja1NpemUgVGhlIG51bWJlciBvZiAzMi1iaXQgd29yZHMgdGhpcyBoYXNoZXIgb3BlcmF0ZXMgb24uIERlZmF1bHQ6IDE2ICg1MTIgYml0cylcblx0ICAgICAqL1xuXHQgICAgdmFyIEhhc2hlciA9IENfbGliLkhhc2hlciA9IEJ1ZmZlcmVkQmxvY2tBbGdvcml0aG0uZXh0ZW5kKHtcblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDb25maWd1cmF0aW9uIG9wdGlvbnMuXG5cdCAgICAgICAgICovXG5cdCAgICAgICAgY2ZnOiBCYXNlLmV4dGVuZCgpLFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogSW5pdGlhbGl6ZXMgYSBuZXdseSBjcmVhdGVkIGhhc2hlci5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBjZmcgKE9wdGlvbmFsKSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIHVzZSBmb3IgdGhpcyBoYXNoIGNvbXB1dGF0aW9uLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgaGFzaGVyID0gQ3J5cHRvSlMuYWxnby5TSEEyNTYuY3JlYXRlKCk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgaW5pdDogZnVuY3Rpb24gKGNmZykge1xuXHQgICAgICAgICAgICAvLyBBcHBseSBjb25maWcgZGVmYXVsdHNcblx0ICAgICAgICAgICAgdGhpcy5jZmcgPSB0aGlzLmNmZy5leHRlbmQoY2ZnKTtcblxuXHQgICAgICAgICAgICAvLyBTZXQgaW5pdGlhbCB2YWx1ZXNcblx0ICAgICAgICAgICAgdGhpcy5yZXNldCgpO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBSZXNldHMgdGhpcyBoYXNoZXIgdG8gaXRzIGluaXRpYWwgc3RhdGUuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIGhhc2hlci5yZXNldCgpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIHJlc2V0OiBmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgICAgIC8vIFJlc2V0IGRhdGEgYnVmZmVyXG5cdCAgICAgICAgICAgIEJ1ZmZlcmVkQmxvY2tBbGdvcml0aG0ucmVzZXQuY2FsbCh0aGlzKTtcblxuXHQgICAgICAgICAgICAvLyBQZXJmb3JtIGNvbmNyZXRlLWhhc2hlciBsb2dpY1xuXHQgICAgICAgICAgICB0aGlzLl9kb1Jlc2V0KCk7XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIFVwZGF0ZXMgdGhpcyBoYXNoZXIgd2l0aCBhIG1lc3NhZ2UuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge1dvcmRBcnJheXxzdHJpbmd9IG1lc3NhZ2VVcGRhdGUgVGhlIG1lc3NhZ2UgdG8gYXBwZW5kLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7SGFzaGVyfSBUaGlzIGhhc2hlci5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgaGFzaGVyLnVwZGF0ZSgnbWVzc2FnZScpO1xuXHQgICAgICAgICAqICAgICBoYXNoZXIudXBkYXRlKHdvcmRBcnJheSk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgdXBkYXRlOiBmdW5jdGlvbiAobWVzc2FnZVVwZGF0ZSkge1xuXHQgICAgICAgICAgICAvLyBBcHBlbmRcblx0ICAgICAgICAgICAgdGhpcy5fYXBwZW5kKG1lc3NhZ2VVcGRhdGUpO1xuXG5cdCAgICAgICAgICAgIC8vIFVwZGF0ZSB0aGUgaGFzaFxuXHQgICAgICAgICAgICB0aGlzLl9wcm9jZXNzKCk7XG5cblx0ICAgICAgICAgICAgLy8gQ2hhaW5hYmxlXG5cdCAgICAgICAgICAgIHJldHVybiB0aGlzO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBGaW5hbGl6ZXMgdGhlIGhhc2ggY29tcHV0YXRpb24uXG5cdCAgICAgICAgICogTm90ZSB0aGF0IHRoZSBmaW5hbGl6ZSBvcGVyYXRpb24gaXMgZWZmZWN0aXZlbHkgYSBkZXN0cnVjdGl2ZSwgcmVhZC1vbmNlIG9wZXJhdGlvbi5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7V29yZEFycmF5fHN0cmluZ30gbWVzc2FnZVVwZGF0ZSAoT3B0aW9uYWwpIEEgZmluYWwgbWVzc2FnZSB1cGRhdGUuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtXb3JkQXJyYXl9IFRoZSBoYXNoLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgaGFzaCA9IGhhc2hlci5maW5hbGl6ZSgpO1xuXHQgICAgICAgICAqICAgICB2YXIgaGFzaCA9IGhhc2hlci5maW5hbGl6ZSgnbWVzc2FnZScpO1xuXHQgICAgICAgICAqICAgICB2YXIgaGFzaCA9IGhhc2hlci5maW5hbGl6ZSh3b3JkQXJyYXkpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIGZpbmFsaXplOiBmdW5jdGlvbiAobWVzc2FnZVVwZGF0ZSkge1xuXHQgICAgICAgICAgICAvLyBGaW5hbCBtZXNzYWdlIHVwZGF0ZVxuXHQgICAgICAgICAgICBpZiAobWVzc2FnZVVwZGF0ZSkge1xuXHQgICAgICAgICAgICAgICAgdGhpcy5fYXBwZW5kKG1lc3NhZ2VVcGRhdGUpO1xuXHQgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgLy8gUGVyZm9ybSBjb25jcmV0ZS1oYXNoZXIgbG9naWNcblx0ICAgICAgICAgICAgdmFyIGhhc2ggPSB0aGlzLl9kb0ZpbmFsaXplKCk7XG5cblx0ICAgICAgICAgICAgcmV0dXJuIGhhc2g7XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIGJsb2NrU2l6ZTogNTEyLzMyLFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogQ3JlYXRlcyBhIHNob3J0Y3V0IGZ1bmN0aW9uIHRvIGEgaGFzaGVyJ3Mgb2JqZWN0IGludGVyZmFjZS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7SGFzaGVyfSBoYXNoZXIgVGhlIGhhc2hlciB0byBjcmVhdGUgYSBoZWxwZXIgZm9yLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7RnVuY3Rpb259IFRoZSBzaG9ydGN1dCBmdW5jdGlvbi5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBzdGF0aWNcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIFNIQTI1NiA9IENyeXB0b0pTLmxpYi5IYXNoZXIuX2NyZWF0ZUhlbHBlcihDcnlwdG9KUy5hbGdvLlNIQTI1Nik7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgX2NyZWF0ZUhlbHBlcjogZnVuY3Rpb24gKGhhc2hlcikge1xuXHQgICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24gKG1lc3NhZ2UsIGNmZykge1xuXHQgICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBoYXNoZXIuaW5pdChjZmcpLmZpbmFsaXplKG1lc3NhZ2UpO1xuXHQgICAgICAgICAgICB9O1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDcmVhdGVzIGEgc2hvcnRjdXQgZnVuY3Rpb24gdG8gdGhlIEhNQUMncyBvYmplY3QgaW50ZXJmYWNlLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtIYXNoZXJ9IGhhc2hlciBUaGUgaGFzaGVyIHRvIHVzZSBpbiB0aGlzIEhNQUMgaGVscGVyLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7RnVuY3Rpb259IFRoZSBzaG9ydGN1dCBmdW5jdGlvbi5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBzdGF0aWNcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIEhtYWNTSEEyNTYgPSBDcnlwdG9KUy5saWIuSGFzaGVyLl9jcmVhdGVIbWFjSGVscGVyKENyeXB0b0pTLmFsZ28uU0hBMjU2KTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICBfY3JlYXRlSG1hY0hlbHBlcjogZnVuY3Rpb24gKGhhc2hlcikge1xuXHQgICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24gKG1lc3NhZ2UsIGtleSkge1xuXHQgICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBDX2FsZ28uSE1BQy5pbml0KGhhc2hlciwga2V5KS5maW5hbGl6ZShtZXNzYWdlKTtcblx0ICAgICAgICAgICAgfTtcblx0ICAgICAgICB9XG5cdCAgICB9KTtcblxuXHQgICAgLyoqXG5cdCAgICAgKiBBbGdvcml0aG0gbmFtZXNwYWNlLlxuXHQgICAgICovXG5cdCAgICB2YXIgQ19hbGdvID0gQy5hbGdvID0ge307XG5cblx0ICAgIHJldHVybiBDO1xuXHR9KE1hdGgpKTtcblxuXG5cdHJldHVybiBDcnlwdG9KUztcblxufSkpOyIsIjsoZnVuY3Rpb24gKHJvb3QsIGZhY3RvcnksIHVuZGVmKSB7XG5cdGlmICh0eXBlb2YgZXhwb3J0cyA9PT0gXCJvYmplY3RcIikge1xuXHRcdC8vIENvbW1vbkpTXG5cdFx0bW9kdWxlLmV4cG9ydHMgPSBleHBvcnRzID0gZmFjdG9yeShyZXF1aXJlKFwiLi9jb3JlXCIpLCByZXF1aXJlKFwiLi94NjQtY29yZVwiKSk7XG5cdH1cblx0ZWxzZSBpZiAodHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIGRlZmluZS5hbWQpIHtcblx0XHQvLyBBTURcblx0XHRkZWZpbmUoW1wiLi9jb3JlXCIsIFwiLi94NjQtY29yZVwiXSwgZmFjdG9yeSk7XG5cdH1cblx0ZWxzZSB7XG5cdFx0Ly8gR2xvYmFsIChicm93c2VyKVxuXHRcdGZhY3Rvcnkocm9vdC5DcnlwdG9KUyk7XG5cdH1cbn0odGhpcywgZnVuY3Rpb24gKENyeXB0b0pTKSB7XG5cblx0KGZ1bmN0aW9uIChNYXRoKSB7XG5cdCAgICAvLyBTaG9ydGN1dHNcblx0ICAgIHZhciBDID0gQ3J5cHRvSlM7XG5cdCAgICB2YXIgQ19saWIgPSBDLmxpYjtcblx0ICAgIHZhciBXb3JkQXJyYXkgPSBDX2xpYi5Xb3JkQXJyYXk7XG5cdCAgICB2YXIgSGFzaGVyID0gQ19saWIuSGFzaGVyO1xuXHQgICAgdmFyIENfeDY0ID0gQy54NjQ7XG5cdCAgICB2YXIgWDY0V29yZCA9IENfeDY0LldvcmQ7XG5cdCAgICB2YXIgQ19hbGdvID0gQy5hbGdvO1xuXG5cdCAgICAvLyBDb25zdGFudHMgdGFibGVzXG5cdCAgICB2YXIgUkhPX09GRlNFVFMgPSBbXTtcblx0ICAgIHZhciBQSV9JTkRFWEVTICA9IFtdO1xuXHQgICAgdmFyIFJPVU5EX0NPTlNUQU5UUyA9IFtdO1xuXG5cdCAgICAvLyBDb21wdXRlIENvbnN0YW50c1xuXHQgICAgKGZ1bmN0aW9uICgpIHtcblx0ICAgICAgICAvLyBDb21wdXRlIHJobyBvZmZzZXQgY29uc3RhbnRzXG5cdCAgICAgICAgdmFyIHggPSAxLCB5ID0gMDtcblx0ICAgICAgICBmb3IgKHZhciB0ID0gMDsgdCA8IDI0OyB0KyspIHtcblx0ICAgICAgICAgICAgUkhPX09GRlNFVFNbeCArIDUgKiB5XSA9ICgodCArIDEpICogKHQgKyAyKSAvIDIpICUgNjQ7XG5cblx0ICAgICAgICAgICAgdmFyIG5ld1ggPSB5ICUgNTtcblx0ICAgICAgICAgICAgdmFyIG5ld1kgPSAoMiAqIHggKyAzICogeSkgJSA1O1xuXHQgICAgICAgICAgICB4ID0gbmV3WDtcblx0ICAgICAgICAgICAgeSA9IG5ld1k7XG5cdCAgICAgICAgfVxuXG5cdCAgICAgICAgLy8gQ29tcHV0ZSBwaSBpbmRleCBjb25zdGFudHNcblx0ICAgICAgICBmb3IgKHZhciB4ID0gMDsgeCA8IDU7IHgrKykge1xuXHQgICAgICAgICAgICBmb3IgKHZhciB5ID0gMDsgeSA8IDU7IHkrKykge1xuXHQgICAgICAgICAgICAgICAgUElfSU5ERVhFU1t4ICsgNSAqIHldID0geSArICgoMiAqIHggKyAzICogeSkgJSA1KSAqIDU7XG5cdCAgICAgICAgICAgIH1cblx0ICAgICAgICB9XG5cblx0ICAgICAgICAvLyBDb21wdXRlIHJvdW5kIGNvbnN0YW50c1xuXHQgICAgICAgIHZhciBMRlNSID0gMHgwMTtcblx0ICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IDI0OyBpKyspIHtcblx0ICAgICAgICAgICAgdmFyIHJvdW5kQ29uc3RhbnRNc3cgPSAwO1xuXHQgICAgICAgICAgICB2YXIgcm91bmRDb25zdGFudExzdyA9IDA7XG5cblx0ICAgICAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCA3OyBqKyspIHtcblx0ICAgICAgICAgICAgICAgIGlmIChMRlNSICYgMHgwMSkge1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciBiaXRQb3NpdGlvbiA9ICgxIDw8IGopIC0gMTtcblx0ICAgICAgICAgICAgICAgICAgICBpZiAoYml0UG9zaXRpb24gPCAzMikge1xuXHQgICAgICAgICAgICAgICAgICAgICAgICByb3VuZENvbnN0YW50THN3IF49IDEgPDwgYml0UG9zaXRpb247XG5cdCAgICAgICAgICAgICAgICAgICAgfSBlbHNlIC8qIGlmIChiaXRQb3NpdGlvbiA+PSAzMikgKi8ge1xuXHQgICAgICAgICAgICAgICAgICAgICAgICByb3VuZENvbnN0YW50TXN3IF49IDEgPDwgKGJpdFBvc2l0aW9uIC0gMzIpO1xuXHQgICAgICAgICAgICAgICAgICAgIH1cblx0ICAgICAgICAgICAgICAgIH1cblxuXHQgICAgICAgICAgICAgICAgLy8gQ29tcHV0ZSBuZXh0IExGU1Jcblx0ICAgICAgICAgICAgICAgIGlmIChMRlNSICYgMHg4MCkge1xuXHQgICAgICAgICAgICAgICAgICAgIC8vIFByaW1pdGl2ZSBwb2x5bm9taWFsIG92ZXIgR0YoMik6IHheOCArIHheNiArIHheNSArIHheNCArIDFcblx0ICAgICAgICAgICAgICAgICAgICBMRlNSID0gKExGU1IgPDwgMSkgXiAweDcxO1xuXHQgICAgICAgICAgICAgICAgfSBlbHNlIHtcblx0ICAgICAgICAgICAgICAgICAgICBMRlNSIDw8PSAxO1xuXHQgICAgICAgICAgICAgICAgfVxuXHQgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgUk9VTkRfQ09OU1RBTlRTW2ldID0gWDY0V29yZC5jcmVhdGUocm91bmRDb25zdGFudE1zdywgcm91bmRDb25zdGFudExzdyk7XG5cdCAgICAgICAgfVxuXHQgICAgfSgpKTtcblxuXHQgICAgLy8gUmV1c2FibGUgb2JqZWN0cyBmb3IgdGVtcG9yYXJ5IHZhbHVlc1xuXHQgICAgdmFyIFQgPSBbXTtcblx0ICAgIChmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCAyNTsgaSsrKSB7XG5cdCAgICAgICAgICAgIFRbaV0gPSBYNjRXb3JkLmNyZWF0ZSgpO1xuXHQgICAgICAgIH1cblx0ICAgIH0oKSk7XG5cblx0ICAgIC8qKlxuXHQgICAgICogU0hBLTMgaGFzaCBhbGdvcml0aG0uXG5cdCAgICAgKi9cblx0ICAgIHZhciBTSEEzID0gQ19hbGdvLlNIQTMgPSBIYXNoZXIuZXh0ZW5kKHtcblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDb25maWd1cmF0aW9uIG9wdGlvbnMuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcHJvcGVydHkge251bWJlcn0gb3V0cHV0TGVuZ3RoXG5cdCAgICAgICAgICogICBUaGUgZGVzaXJlZCBudW1iZXIgb2YgYml0cyBpbiB0aGUgb3V0cHV0IGhhc2guXG5cdCAgICAgICAgICogICBPbmx5IHZhbHVlcyBwZXJtaXR0ZWQgYXJlOiAyMjQsIDI1NiwgMzg0LCA1MTIuXG5cdCAgICAgICAgICogICBEZWZhdWx0OiA1MTJcblx0ICAgICAgICAgKi9cblx0ICAgICAgICBjZmc6IEhhc2hlci5jZmcuZXh0ZW5kKHtcblx0ICAgICAgICAgICAgb3V0cHV0TGVuZ3RoOiA1MTJcblx0ICAgICAgICB9KSxcblxuXHQgICAgICAgIF9kb1Jlc2V0OiBmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgICAgIHZhciBzdGF0ZSA9IHRoaXMuX3N0YXRlID0gW11cblx0ICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCAyNTsgaSsrKSB7XG5cdCAgICAgICAgICAgICAgICBzdGF0ZVtpXSA9IG5ldyBYNjRXb3JkLmluaXQoKTtcblx0ICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgIHRoaXMuYmxvY2tTaXplID0gKDE2MDAgLSAyICogdGhpcy5jZmcub3V0cHV0TGVuZ3RoKSAvIDMyO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICBfZG9Qcm9jZXNzQmxvY2s6IGZ1bmN0aW9uIChNLCBvZmZzZXQpIHtcblx0ICAgICAgICAgICAgLy8gU2hvcnRjdXRzXG5cdCAgICAgICAgICAgIHZhciBzdGF0ZSA9IHRoaXMuX3N0YXRlO1xuXHQgICAgICAgICAgICB2YXIgbkJsb2NrU2l6ZUxhbmVzID0gdGhpcy5ibG9ja1NpemUgLyAyO1xuXG5cdCAgICAgICAgICAgIC8vIEFic29yYlxuXHQgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG5CbG9ja1NpemVMYW5lczsgaSsrKSB7XG5cdCAgICAgICAgICAgICAgICAvLyBTaG9ydGN1dHNcblx0ICAgICAgICAgICAgICAgIHZhciBNMmkgID0gTVtvZmZzZXQgKyAyICogaV07XG5cdCAgICAgICAgICAgICAgICB2YXIgTTJpMSA9IE1bb2Zmc2V0ICsgMiAqIGkgKyAxXTtcblxuXHQgICAgICAgICAgICAgICAgLy8gU3dhcCBlbmRpYW5cblx0ICAgICAgICAgICAgICAgIE0yaSA9IChcblx0ICAgICAgICAgICAgICAgICAgICAoKChNMmkgPDwgOCkgIHwgKE0yaSA+Pj4gMjQpKSAmIDB4MDBmZjAwZmYpIHxcblx0ICAgICAgICAgICAgICAgICAgICAoKChNMmkgPDwgMjQpIHwgKE0yaSA+Pj4gOCkpICAmIDB4ZmYwMGZmMDApXG5cdCAgICAgICAgICAgICAgICApO1xuXHQgICAgICAgICAgICAgICAgTTJpMSA9IChcblx0ICAgICAgICAgICAgICAgICAgICAoKChNMmkxIDw8IDgpICB8IChNMmkxID4+PiAyNCkpICYgMHgwMGZmMDBmZikgfFxuXHQgICAgICAgICAgICAgICAgICAgICgoKE0yaTEgPDwgMjQpIHwgKE0yaTEgPj4+IDgpKSAgJiAweGZmMDBmZjAwKVxuXHQgICAgICAgICAgICAgICAgKTtcblxuXHQgICAgICAgICAgICAgICAgLy8gQWJzb3JiIG1lc3NhZ2UgaW50byBzdGF0ZVxuXHQgICAgICAgICAgICAgICAgdmFyIGxhbmUgPSBzdGF0ZVtpXTtcblx0ICAgICAgICAgICAgICAgIGxhbmUuaGlnaCBePSBNMmkxO1xuXHQgICAgICAgICAgICAgICAgbGFuZS5sb3cgIF49IE0yaTtcblx0ICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgIC8vIFJvdW5kc1xuXHQgICAgICAgICAgICBmb3IgKHZhciByb3VuZCA9IDA7IHJvdW5kIDwgMjQ7IHJvdW5kKyspIHtcblx0ICAgICAgICAgICAgICAgIC8vIFRoZXRhXG5cdCAgICAgICAgICAgICAgICBmb3IgKHZhciB4ID0gMDsgeCA8IDU7IHgrKykge1xuXHQgICAgICAgICAgICAgICAgICAgIC8vIE1peCBjb2x1bW4gbGFuZXNcblx0ICAgICAgICAgICAgICAgICAgICB2YXIgdE1zdyA9IDAsIHRMc3cgPSAwO1xuXHQgICAgICAgICAgICAgICAgICAgIGZvciAodmFyIHkgPSAwOyB5IDwgNTsgeSsrKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIHZhciBsYW5lID0gc3RhdGVbeCArIDUgKiB5XTtcblx0ICAgICAgICAgICAgICAgICAgICAgICAgdE1zdyBePSBsYW5lLmhpZ2g7XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIHRMc3cgXj0gbGFuZS5sb3c7XG5cdCAgICAgICAgICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgICAgICAgICAgLy8gVGVtcG9yYXJ5IHZhbHVlc1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciBUeCA9IFRbeF07XG5cdCAgICAgICAgICAgICAgICAgICAgVHguaGlnaCA9IHRNc3c7XG5cdCAgICAgICAgICAgICAgICAgICAgVHgubG93ICA9IHRMc3c7XG5cdCAgICAgICAgICAgICAgICB9XG5cdCAgICAgICAgICAgICAgICBmb3IgKHZhciB4ID0gMDsgeCA8IDU7IHgrKykge1xuXHQgICAgICAgICAgICAgICAgICAgIC8vIFNob3J0Y3V0c1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciBUeDQgPSBUWyh4ICsgNCkgJSA1XTtcblx0ICAgICAgICAgICAgICAgICAgICB2YXIgVHgxID0gVFsoeCArIDEpICUgNV07XG5cdCAgICAgICAgICAgICAgICAgICAgdmFyIFR4MU1zdyA9IFR4MS5oaWdoO1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciBUeDFMc3cgPSBUeDEubG93O1xuXG5cdCAgICAgICAgICAgICAgICAgICAgLy8gTWl4IHN1cnJvdW5kaW5nIGNvbHVtbnNcblx0ICAgICAgICAgICAgICAgICAgICB2YXIgdE1zdyA9IFR4NC5oaWdoIF4gKChUeDFNc3cgPDwgMSkgfCAoVHgxTHN3ID4+PiAzMSkpO1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciB0THN3ID0gVHg0LmxvdyAgXiAoKFR4MUxzdyA8PCAxKSB8IChUeDFNc3cgPj4+IDMxKSk7XG5cdCAgICAgICAgICAgICAgICAgICAgZm9yICh2YXIgeSA9IDA7IHkgPCA1OyB5KyspIHtcblx0ICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGxhbmUgPSBzdGF0ZVt4ICsgNSAqIHldO1xuXHQgICAgICAgICAgICAgICAgICAgICAgICBsYW5lLmhpZ2ggXj0gdE1zdztcblx0ICAgICAgICAgICAgICAgICAgICAgICAgbGFuZS5sb3cgIF49IHRMc3c7XG5cdCAgICAgICAgICAgICAgICAgICAgfVxuXHQgICAgICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgICAgICAvLyBSaG8gUGlcblx0ICAgICAgICAgICAgICAgIGZvciAodmFyIGxhbmVJbmRleCA9IDE7IGxhbmVJbmRleCA8IDI1OyBsYW5lSW5kZXgrKykge1xuXHQgICAgICAgICAgICAgICAgICAgIC8vIFNob3J0Y3V0c1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciBsYW5lID0gc3RhdGVbbGFuZUluZGV4XTtcblx0ICAgICAgICAgICAgICAgICAgICB2YXIgbGFuZU1zdyA9IGxhbmUuaGlnaDtcblx0ICAgICAgICAgICAgICAgICAgICB2YXIgbGFuZUxzdyA9IGxhbmUubG93O1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciByaG9PZmZzZXQgPSBSSE9fT0ZGU0VUU1tsYW5lSW5kZXhdO1xuXG5cdCAgICAgICAgICAgICAgICAgICAgLy8gUm90YXRlIGxhbmVzXG5cdCAgICAgICAgICAgICAgICAgICAgaWYgKHJob09mZnNldCA8IDMyKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIHZhciB0TXN3ID0gKGxhbmVNc3cgPDwgcmhvT2Zmc2V0KSB8IChsYW5lTHN3ID4+PiAoMzIgLSByaG9PZmZzZXQpKTtcblx0ICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHRMc3cgPSAobGFuZUxzdyA8PCByaG9PZmZzZXQpIHwgKGxhbmVNc3cgPj4+ICgzMiAtIHJob09mZnNldCkpO1xuXHQgICAgICAgICAgICAgICAgICAgIH0gZWxzZSAvKiBpZiAocmhvT2Zmc2V0ID49IDMyKSAqLyB7XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIHZhciB0TXN3ID0gKGxhbmVMc3cgPDwgKHJob09mZnNldCAtIDMyKSkgfCAobGFuZU1zdyA+Pj4gKDY0IC0gcmhvT2Zmc2V0KSk7XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIHZhciB0THN3ID0gKGxhbmVNc3cgPDwgKHJob09mZnNldCAtIDMyKSkgfCAobGFuZUxzdyA+Pj4gKDY0IC0gcmhvT2Zmc2V0KSk7XG5cdCAgICAgICAgICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgICAgICAgICAgLy8gVHJhbnNwb3NlIGxhbmVzXG5cdCAgICAgICAgICAgICAgICAgICAgdmFyIFRQaUxhbmUgPSBUW1BJX0lOREVYRVNbbGFuZUluZGV4XV07XG5cdCAgICAgICAgICAgICAgICAgICAgVFBpTGFuZS5oaWdoID0gdE1zdztcblx0ICAgICAgICAgICAgICAgICAgICBUUGlMYW5lLmxvdyAgPSB0THN3O1xuXHQgICAgICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgICAgICAvLyBSaG8gcGkgYXQgeCA9IHkgPSAwXG5cdCAgICAgICAgICAgICAgICB2YXIgVDAgPSBUWzBdO1xuXHQgICAgICAgICAgICAgICAgdmFyIHN0YXRlMCA9IHN0YXRlWzBdO1xuXHQgICAgICAgICAgICAgICAgVDAuaGlnaCA9IHN0YXRlMC5oaWdoO1xuXHQgICAgICAgICAgICAgICAgVDAubG93ICA9IHN0YXRlMC5sb3c7XG5cblx0ICAgICAgICAgICAgICAgIC8vIENoaVxuXHQgICAgICAgICAgICAgICAgZm9yICh2YXIgeCA9IDA7IHggPCA1OyB4KyspIHtcblx0ICAgICAgICAgICAgICAgICAgICBmb3IgKHZhciB5ID0gMDsgeSA8IDU7IHkrKykge1xuXHQgICAgICAgICAgICAgICAgICAgICAgICAvLyBTaG9ydGN1dHNcblx0ICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGxhbmVJbmRleCA9IHggKyA1ICogeTtcblx0ICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGxhbmUgPSBzdGF0ZVtsYW5lSW5kZXhdO1xuXHQgICAgICAgICAgICAgICAgICAgICAgICB2YXIgVExhbmUgPSBUW2xhbmVJbmRleF07XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIHZhciBUeDFMYW5lID0gVFsoKHggKyAxKSAlIDUpICsgNSAqIHldO1xuXHQgICAgICAgICAgICAgICAgICAgICAgICB2YXIgVHgyTGFuZSA9IFRbKCh4ICsgMikgJSA1KSArIDUgKiB5XTtcblxuXHQgICAgICAgICAgICAgICAgICAgICAgICAvLyBNaXggcm93c1xuXHQgICAgICAgICAgICAgICAgICAgICAgICBsYW5lLmhpZ2ggPSBUTGFuZS5oaWdoIF4gKH5UeDFMYW5lLmhpZ2ggJiBUeDJMYW5lLmhpZ2gpO1xuXHQgICAgICAgICAgICAgICAgICAgICAgICBsYW5lLmxvdyAgPSBUTGFuZS5sb3cgIF4gKH5UeDFMYW5lLmxvdyAgJiBUeDJMYW5lLmxvdyk7XG5cdCAgICAgICAgICAgICAgICAgICAgfVxuXHQgICAgICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgICAgICAvLyBJb3RhXG5cdCAgICAgICAgICAgICAgICB2YXIgbGFuZSA9IHN0YXRlWzBdO1xuXHQgICAgICAgICAgICAgICAgdmFyIHJvdW5kQ29uc3RhbnQgPSBST1VORF9DT05TVEFOVFNbcm91bmRdO1xuXHQgICAgICAgICAgICAgICAgbGFuZS5oaWdoIF49IHJvdW5kQ29uc3RhbnQuaGlnaDtcblx0ICAgICAgICAgICAgICAgIGxhbmUubG93ICBePSByb3VuZENvbnN0YW50Lmxvdzs7XG5cdCAgICAgICAgICAgIH1cblx0ICAgICAgICB9LFxuXG5cdCAgICAgICAgX2RvRmluYWxpemU6IGZ1bmN0aW9uICgpIHtcblx0ICAgICAgICAgICAgLy8gU2hvcnRjdXRzXG5cdCAgICAgICAgICAgIHZhciBkYXRhID0gdGhpcy5fZGF0YTtcblx0ICAgICAgICAgICAgdmFyIGRhdGFXb3JkcyA9IGRhdGEud29yZHM7XG5cdCAgICAgICAgICAgIHZhciBuQml0c1RvdGFsID0gdGhpcy5fbkRhdGFCeXRlcyAqIDg7XG5cdCAgICAgICAgICAgIHZhciBuQml0c0xlZnQgPSBkYXRhLnNpZ0J5dGVzICogODtcblx0ICAgICAgICAgICAgdmFyIGJsb2NrU2l6ZUJpdHMgPSB0aGlzLmJsb2NrU2l6ZSAqIDMyO1xuXG5cdCAgICAgICAgICAgIC8vIEFkZCBwYWRkaW5nXG5cdCAgICAgICAgICAgIGRhdGFXb3Jkc1tuQml0c0xlZnQgPj4+IDVdIHw9IDB4MSA8PCAoMjQgLSBuQml0c0xlZnQgJSAzMik7XG5cdCAgICAgICAgICAgIGRhdGFXb3Jkc1soKE1hdGguY2VpbCgobkJpdHNMZWZ0ICsgMSkgLyBibG9ja1NpemVCaXRzKSAqIGJsb2NrU2l6ZUJpdHMpID4+PiA1KSAtIDFdIHw9IDB4ODA7XG5cdCAgICAgICAgICAgIGRhdGEuc2lnQnl0ZXMgPSBkYXRhV29yZHMubGVuZ3RoICogNDtcblxuXHQgICAgICAgICAgICAvLyBIYXNoIGZpbmFsIGJsb2Nrc1xuXHQgICAgICAgICAgICB0aGlzLl9wcm9jZXNzKCk7XG5cblx0ICAgICAgICAgICAgLy8gU2hvcnRjdXRzXG5cdCAgICAgICAgICAgIHZhciBzdGF0ZSA9IHRoaXMuX3N0YXRlO1xuXHQgICAgICAgICAgICB2YXIgb3V0cHV0TGVuZ3RoQnl0ZXMgPSB0aGlzLmNmZy5vdXRwdXRMZW5ndGggLyA4O1xuXHQgICAgICAgICAgICB2YXIgb3V0cHV0TGVuZ3RoTGFuZXMgPSBvdXRwdXRMZW5ndGhCeXRlcyAvIDg7XG5cblx0ICAgICAgICAgICAgLy8gU3F1ZWV6ZVxuXHQgICAgICAgICAgICB2YXIgaGFzaFdvcmRzID0gW107XG5cdCAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgb3V0cHV0TGVuZ3RoTGFuZXM7IGkrKykge1xuXHQgICAgICAgICAgICAgICAgLy8gU2hvcnRjdXRzXG5cdCAgICAgICAgICAgICAgICB2YXIgbGFuZSA9IHN0YXRlW2ldO1xuXHQgICAgICAgICAgICAgICAgdmFyIGxhbmVNc3cgPSBsYW5lLmhpZ2g7XG5cdCAgICAgICAgICAgICAgICB2YXIgbGFuZUxzdyA9IGxhbmUubG93O1xuXG5cdCAgICAgICAgICAgICAgICAvLyBTd2FwIGVuZGlhblxuXHQgICAgICAgICAgICAgICAgbGFuZU1zdyA9IChcblx0ICAgICAgICAgICAgICAgICAgICAoKChsYW5lTXN3IDw8IDgpICB8IChsYW5lTXN3ID4+PiAyNCkpICYgMHgwMGZmMDBmZikgfFxuXHQgICAgICAgICAgICAgICAgICAgICgoKGxhbmVNc3cgPDwgMjQpIHwgKGxhbmVNc3cgPj4+IDgpKSAgJiAweGZmMDBmZjAwKVxuXHQgICAgICAgICAgICAgICAgKTtcblx0ICAgICAgICAgICAgICAgIGxhbmVMc3cgPSAoXG5cdCAgICAgICAgICAgICAgICAgICAgKCgobGFuZUxzdyA8PCA4KSAgfCAobGFuZUxzdyA+Pj4gMjQpKSAmIDB4MDBmZjAwZmYpIHxcblx0ICAgICAgICAgICAgICAgICAgICAoKChsYW5lTHN3IDw8IDI0KSB8IChsYW5lTHN3ID4+PiA4KSkgICYgMHhmZjAwZmYwMClcblx0ICAgICAgICAgICAgICAgICk7XG5cblx0ICAgICAgICAgICAgICAgIC8vIFNxdWVlemUgc3RhdGUgdG8gcmV0cmlldmUgaGFzaFxuXHQgICAgICAgICAgICAgICAgaGFzaFdvcmRzLnB1c2gobGFuZUxzdyk7XG5cdCAgICAgICAgICAgICAgICBoYXNoV29yZHMucHVzaChsYW5lTXN3KTtcblx0ICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgIC8vIFJldHVybiBmaW5hbCBjb21wdXRlZCBoYXNoXG5cdCAgICAgICAgICAgIHJldHVybiBuZXcgV29yZEFycmF5LmluaXQoaGFzaFdvcmRzLCBvdXRwdXRMZW5ndGhCeXRlcyk7XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIGNsb25lOiBmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgICAgIHZhciBjbG9uZSA9IEhhc2hlci5jbG9uZS5jYWxsKHRoaXMpO1xuXG5cdCAgICAgICAgICAgIHZhciBzdGF0ZSA9IGNsb25lLl9zdGF0ZSA9IHRoaXMuX3N0YXRlLnNsaWNlKDApO1xuXHQgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IDI1OyBpKyspIHtcblx0ICAgICAgICAgICAgICAgIHN0YXRlW2ldID0gc3RhdGVbaV0uY2xvbmUoKTtcblx0ICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgIHJldHVybiBjbG9uZTtcblx0ICAgICAgICB9XG5cdCAgICB9KTtcblxuXHQgICAgLyoqXG5cdCAgICAgKiBTaG9ydGN1dCBmdW5jdGlvbiB0byB0aGUgaGFzaGVyJ3Mgb2JqZWN0IGludGVyZmFjZS5cblx0ICAgICAqXG5cdCAgICAgKiBAcGFyYW0ge1dvcmRBcnJheXxzdHJpbmd9IG1lc3NhZ2UgVGhlIG1lc3NhZ2UgdG8gaGFzaC5cblx0ICAgICAqXG5cdCAgICAgKiBAcmV0dXJuIHtXb3JkQXJyYXl9IFRoZSBoYXNoLlxuXHQgICAgICpcblx0ICAgICAqIEBzdGF0aWNcblx0ICAgICAqXG5cdCAgICAgKiBAZXhhbXBsZVxuXHQgICAgICpcblx0ICAgICAqICAgICB2YXIgaGFzaCA9IENyeXB0b0pTLlNIQTMoJ21lc3NhZ2UnKTtcblx0ICAgICAqICAgICB2YXIgaGFzaCA9IENyeXB0b0pTLlNIQTMod29yZEFycmF5KTtcblx0ICAgICAqL1xuXHQgICAgQy5TSEEzID0gSGFzaGVyLl9jcmVhdGVIZWxwZXIoU0hBMyk7XG5cblx0ICAgIC8qKlxuXHQgICAgICogU2hvcnRjdXQgZnVuY3Rpb24gdG8gdGhlIEhNQUMncyBvYmplY3QgaW50ZXJmYWNlLlxuXHQgICAgICpcblx0ICAgICAqIEBwYXJhbSB7V29yZEFycmF5fHN0cmluZ30gbWVzc2FnZSBUaGUgbWVzc2FnZSB0byBoYXNoLlxuXHQgICAgICogQHBhcmFtIHtXb3JkQXJyYXl8c3RyaW5nfSBrZXkgVGhlIHNlY3JldCBrZXkuXG5cdCAgICAgKlxuXHQgICAgICogQHJldHVybiB7V29yZEFycmF5fSBUaGUgSE1BQy5cblx0ICAgICAqXG5cdCAgICAgKiBAc3RhdGljXG5cdCAgICAgKlxuXHQgICAgICogQGV4YW1wbGVcblx0ICAgICAqXG5cdCAgICAgKiAgICAgdmFyIGhtYWMgPSBDcnlwdG9KUy5IbWFjU0hBMyhtZXNzYWdlLCBrZXkpO1xuXHQgICAgICovXG5cdCAgICBDLkhtYWNTSEEzID0gSGFzaGVyLl9jcmVhdGVIbWFjSGVscGVyKFNIQTMpO1xuXHR9KE1hdGgpKTtcblxuXG5cdHJldHVybiBDcnlwdG9KUy5TSEEzO1xuXG59KSk7IiwiOyhmdW5jdGlvbiAocm9vdCwgZmFjdG9yeSkge1xuXHRpZiAodHlwZW9mIGV4cG9ydHMgPT09IFwib2JqZWN0XCIpIHtcblx0XHQvLyBDb21tb25KU1xuXHRcdG1vZHVsZS5leHBvcnRzID0gZXhwb3J0cyA9IGZhY3RvcnkocmVxdWlyZShcIi4vY29yZVwiKSk7XG5cdH1cblx0ZWxzZSBpZiAodHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIGRlZmluZS5hbWQpIHtcblx0XHQvLyBBTURcblx0XHRkZWZpbmUoW1wiLi9jb3JlXCJdLCBmYWN0b3J5KTtcblx0fVxuXHRlbHNlIHtcblx0XHQvLyBHbG9iYWwgKGJyb3dzZXIpXG5cdFx0ZmFjdG9yeShyb290LkNyeXB0b0pTKTtcblx0fVxufSh0aGlzLCBmdW5jdGlvbiAoQ3J5cHRvSlMpIHtcblxuXHQoZnVuY3Rpb24gKHVuZGVmaW5lZCkge1xuXHQgICAgLy8gU2hvcnRjdXRzXG5cdCAgICB2YXIgQyA9IENyeXB0b0pTO1xuXHQgICAgdmFyIENfbGliID0gQy5saWI7XG5cdCAgICB2YXIgQmFzZSA9IENfbGliLkJhc2U7XG5cdCAgICB2YXIgWDMyV29yZEFycmF5ID0gQ19saWIuV29yZEFycmF5O1xuXG5cdCAgICAvKipcblx0ICAgICAqIHg2NCBuYW1lc3BhY2UuXG5cdCAgICAgKi9cblx0ICAgIHZhciBDX3g2NCA9IEMueDY0ID0ge307XG5cblx0ICAgIC8qKlxuXHQgICAgICogQSA2NC1iaXQgd29yZC5cblx0ICAgICAqL1xuXHQgICAgdmFyIFg2NFdvcmQgPSBDX3g2NC5Xb3JkID0gQmFzZS5leHRlbmQoe1xuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIEluaXRpYWxpemVzIGEgbmV3bHkgY3JlYXRlZCA2NC1iaXQgd29yZC5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBoaWdoIFRoZSBoaWdoIDMyIGJpdHMuXG5cdCAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGxvdyBUaGUgbG93IDMyIGJpdHMuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciB4NjRXb3JkID0gQ3J5cHRvSlMueDY0LldvcmQuY3JlYXRlKDB4MDAwMTAyMDMsIDB4MDQwNTA2MDcpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIGluaXQ6IGZ1bmN0aW9uIChoaWdoLCBsb3cpIHtcblx0ICAgICAgICAgICAgdGhpcy5oaWdoID0gaGlnaDtcblx0ICAgICAgICAgICAgdGhpcy5sb3cgPSBsb3c7XG5cdCAgICAgICAgfVxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogQml0d2lzZSBOT1RzIHRoaXMgd29yZC5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge1g2NFdvcmR9IEEgbmV3IHg2NC1Xb3JkIG9iamVjdCBhZnRlciBuZWdhdGluZy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIG5lZ2F0ZWQgPSB4NjRXb3JkLm5vdCgpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIC8vIG5vdDogZnVuY3Rpb24gKCkge1xuXHQgICAgICAgICAgICAvLyB2YXIgaGlnaCA9IH50aGlzLmhpZ2g7XG5cdCAgICAgICAgICAgIC8vIHZhciBsb3cgPSB+dGhpcy5sb3c7XG5cblx0ICAgICAgICAgICAgLy8gcmV0dXJuIFg2NFdvcmQuY3JlYXRlKGhpZ2gsIGxvdyk7XG5cdCAgICAgICAgLy8gfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIEJpdHdpc2UgQU5EcyB0aGlzIHdvcmQgd2l0aCB0aGUgcGFzc2VkIHdvcmQuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge1g2NFdvcmR9IHdvcmQgVGhlIHg2NC1Xb3JkIHRvIEFORCB3aXRoIHRoaXMgd29yZC5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge1g2NFdvcmR9IEEgbmV3IHg2NC1Xb3JkIG9iamVjdCBhZnRlciBBTkRpbmcuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciBhbmRlZCA9IHg2NFdvcmQuYW5kKGFub3RoZXJYNjRXb3JkKTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICAvLyBhbmQ6IGZ1bmN0aW9uICh3b3JkKSB7XG5cdCAgICAgICAgICAgIC8vIHZhciBoaWdoID0gdGhpcy5oaWdoICYgd29yZC5oaWdoO1xuXHQgICAgICAgICAgICAvLyB2YXIgbG93ID0gdGhpcy5sb3cgJiB3b3JkLmxvdztcblxuXHQgICAgICAgICAgICAvLyByZXR1cm4gWDY0V29yZC5jcmVhdGUoaGlnaCwgbG93KTtcblx0ICAgICAgICAvLyB9LFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogQml0d2lzZSBPUnMgdGhpcyB3b3JkIHdpdGggdGhlIHBhc3NlZCB3b3JkLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtYNjRXb3JkfSB3b3JkIFRoZSB4NjQtV29yZCB0byBPUiB3aXRoIHRoaXMgd29yZC5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge1g2NFdvcmR9IEEgbmV3IHg2NC1Xb3JkIG9iamVjdCBhZnRlciBPUmluZy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIG9yZWQgPSB4NjRXb3JkLm9yKGFub3RoZXJYNjRXb3JkKTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICAvLyBvcjogZnVuY3Rpb24gKHdvcmQpIHtcblx0ICAgICAgICAgICAgLy8gdmFyIGhpZ2ggPSB0aGlzLmhpZ2ggfCB3b3JkLmhpZ2g7XG5cdCAgICAgICAgICAgIC8vIHZhciBsb3cgPSB0aGlzLmxvdyB8IHdvcmQubG93O1xuXG5cdCAgICAgICAgICAgIC8vIHJldHVybiBYNjRXb3JkLmNyZWF0ZShoaWdoLCBsb3cpO1xuXHQgICAgICAgIC8vIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBCaXR3aXNlIFhPUnMgdGhpcyB3b3JkIHdpdGggdGhlIHBhc3NlZCB3b3JkLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtYNjRXb3JkfSB3b3JkIFRoZSB4NjQtV29yZCB0byBYT1Igd2l0aCB0aGlzIHdvcmQuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtYNjRXb3JkfSBBIG5ldyB4NjQtV29yZCBvYmplY3QgYWZ0ZXIgWE9SaW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgeG9yZWQgPSB4NjRXb3JkLnhvcihhbm90aGVyWDY0V29yZCk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgLy8geG9yOiBmdW5jdGlvbiAod29yZCkge1xuXHQgICAgICAgICAgICAvLyB2YXIgaGlnaCA9IHRoaXMuaGlnaCBeIHdvcmQuaGlnaDtcblx0ICAgICAgICAgICAgLy8gdmFyIGxvdyA9IHRoaXMubG93IF4gd29yZC5sb3c7XG5cblx0ICAgICAgICAgICAgLy8gcmV0dXJuIFg2NFdvcmQuY3JlYXRlKGhpZ2gsIGxvdyk7XG5cdCAgICAgICAgLy8gfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIFNoaWZ0cyB0aGlzIHdvcmQgbiBiaXRzIHRvIHRoZSBsZWZ0LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IG4gVGhlIG51bWJlciBvZiBiaXRzIHRvIHNoaWZ0LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7WDY0V29yZH0gQSBuZXcgeDY0LVdvcmQgb2JqZWN0IGFmdGVyIHNoaWZ0aW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgc2hpZnRlZCA9IHg2NFdvcmQuc2hpZnRMKDI1KTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICAvLyBzaGlmdEw6IGZ1bmN0aW9uIChuKSB7XG5cdCAgICAgICAgICAgIC8vIGlmIChuIDwgMzIpIHtcblx0ICAgICAgICAgICAgICAgIC8vIHZhciBoaWdoID0gKHRoaXMuaGlnaCA8PCBuKSB8ICh0aGlzLmxvdyA+Pj4gKDMyIC0gbikpO1xuXHQgICAgICAgICAgICAgICAgLy8gdmFyIGxvdyA9IHRoaXMubG93IDw8IG47XG5cdCAgICAgICAgICAgIC8vIH0gZWxzZSB7XG5cdCAgICAgICAgICAgICAgICAvLyB2YXIgaGlnaCA9IHRoaXMubG93IDw8IChuIC0gMzIpO1xuXHQgICAgICAgICAgICAgICAgLy8gdmFyIGxvdyA9IDA7XG5cdCAgICAgICAgICAgIC8vIH1cblxuXHQgICAgICAgICAgICAvLyByZXR1cm4gWDY0V29yZC5jcmVhdGUoaGlnaCwgbG93KTtcblx0ICAgICAgICAvLyB9LFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogU2hpZnRzIHRoaXMgd29yZCBuIGJpdHMgdG8gdGhlIHJpZ2h0LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IG4gVGhlIG51bWJlciBvZiBiaXRzIHRvIHNoaWZ0LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7WDY0V29yZH0gQSBuZXcgeDY0LVdvcmQgb2JqZWN0IGFmdGVyIHNoaWZ0aW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgc2hpZnRlZCA9IHg2NFdvcmQuc2hpZnRSKDcpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIC8vIHNoaWZ0UjogZnVuY3Rpb24gKG4pIHtcblx0ICAgICAgICAgICAgLy8gaWYgKG4gPCAzMikge1xuXHQgICAgICAgICAgICAgICAgLy8gdmFyIGxvdyA9ICh0aGlzLmxvdyA+Pj4gbikgfCAodGhpcy5oaWdoIDw8ICgzMiAtIG4pKTtcblx0ICAgICAgICAgICAgICAgIC8vIHZhciBoaWdoID0gdGhpcy5oaWdoID4+PiBuO1xuXHQgICAgICAgICAgICAvLyB9IGVsc2Uge1xuXHQgICAgICAgICAgICAgICAgLy8gdmFyIGxvdyA9IHRoaXMuaGlnaCA+Pj4gKG4gLSAzMik7XG5cdCAgICAgICAgICAgICAgICAvLyB2YXIgaGlnaCA9IDA7XG5cdCAgICAgICAgICAgIC8vIH1cblxuXHQgICAgICAgICAgICAvLyByZXR1cm4gWDY0V29yZC5jcmVhdGUoaGlnaCwgbG93KTtcblx0ICAgICAgICAvLyB9LFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogUm90YXRlcyB0aGlzIHdvcmQgbiBiaXRzIHRvIHRoZSBsZWZ0LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IG4gVGhlIG51bWJlciBvZiBiaXRzIHRvIHJvdGF0ZS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge1g2NFdvcmR9IEEgbmV3IHg2NC1Xb3JkIG9iamVjdCBhZnRlciByb3RhdGluZy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIHJvdGF0ZWQgPSB4NjRXb3JkLnJvdEwoMjUpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIC8vIHJvdEw6IGZ1bmN0aW9uIChuKSB7XG5cdCAgICAgICAgICAgIC8vIHJldHVybiB0aGlzLnNoaWZ0TChuKS5vcih0aGlzLnNoaWZ0Uig2NCAtIG4pKTtcblx0ICAgICAgICAvLyB9LFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogUm90YXRlcyB0aGlzIHdvcmQgbiBiaXRzIHRvIHRoZSByaWdodC5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBuIFRoZSBudW1iZXIgb2YgYml0cyB0byByb3RhdGUuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtYNjRXb3JkfSBBIG5ldyB4NjQtV29yZCBvYmplY3QgYWZ0ZXIgcm90YXRpbmcuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciByb3RhdGVkID0geDY0V29yZC5yb3RSKDcpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIC8vIHJvdFI6IGZ1bmN0aW9uIChuKSB7XG5cdCAgICAgICAgICAgIC8vIHJldHVybiB0aGlzLnNoaWZ0UihuKS5vcih0aGlzLnNoaWZ0TCg2NCAtIG4pKTtcblx0ICAgICAgICAvLyB9LFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogQWRkcyB0aGlzIHdvcmQgd2l0aCB0aGUgcGFzc2VkIHdvcmQuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge1g2NFdvcmR9IHdvcmQgVGhlIHg2NC1Xb3JkIHRvIGFkZCB3aXRoIHRoaXMgd29yZC5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge1g2NFdvcmR9IEEgbmV3IHg2NC1Xb3JkIG9iamVjdCBhZnRlciBhZGRpbmcuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciBhZGRlZCA9IHg2NFdvcmQuYWRkKGFub3RoZXJYNjRXb3JkKTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICAvLyBhZGQ6IGZ1bmN0aW9uICh3b3JkKSB7XG5cdCAgICAgICAgICAgIC8vIHZhciBsb3cgPSAodGhpcy5sb3cgKyB3b3JkLmxvdykgfCAwO1xuXHQgICAgICAgICAgICAvLyB2YXIgY2FycnkgPSAobG93ID4+PiAwKSA8ICh0aGlzLmxvdyA+Pj4gMCkgPyAxIDogMDtcblx0ICAgICAgICAgICAgLy8gdmFyIGhpZ2ggPSAodGhpcy5oaWdoICsgd29yZC5oaWdoICsgY2FycnkpIHwgMDtcblxuXHQgICAgICAgICAgICAvLyByZXR1cm4gWDY0V29yZC5jcmVhdGUoaGlnaCwgbG93KTtcblx0ICAgICAgICAvLyB9XG5cdCAgICB9KTtcblxuXHQgICAgLyoqXG5cdCAgICAgKiBBbiBhcnJheSBvZiA2NC1iaXQgd29yZHMuXG5cdCAgICAgKlxuXHQgICAgICogQHByb3BlcnR5IHtBcnJheX0gd29yZHMgVGhlIGFycmF5IG9mIENyeXB0b0pTLng2NC5Xb3JkIG9iamVjdHMuXG5cdCAgICAgKiBAcHJvcGVydHkge251bWJlcn0gc2lnQnl0ZXMgVGhlIG51bWJlciBvZiBzaWduaWZpY2FudCBieXRlcyBpbiB0aGlzIHdvcmQgYXJyYXkuXG5cdCAgICAgKi9cblx0ICAgIHZhciBYNjRXb3JkQXJyYXkgPSBDX3g2NC5Xb3JkQXJyYXkgPSBCYXNlLmV4dGVuZCh7XG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogSW5pdGlhbGl6ZXMgYSBuZXdseSBjcmVhdGVkIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge0FycmF5fSB3b3JkcyAoT3B0aW9uYWwpIEFuIGFycmF5IG9mIENyeXB0b0pTLng2NC5Xb3JkIG9iamVjdHMuXG5cdCAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IHNpZ0J5dGVzIChPcHRpb25hbCkgVGhlIG51bWJlciBvZiBzaWduaWZpY2FudCBieXRlcyBpbiB0aGUgd29yZHMuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciB3b3JkQXJyYXkgPSBDcnlwdG9KUy54NjQuV29yZEFycmF5LmNyZWF0ZSgpO1xuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciB3b3JkQXJyYXkgPSBDcnlwdG9KUy54NjQuV29yZEFycmF5LmNyZWF0ZShbXG5cdCAgICAgICAgICogICAgICAgICBDcnlwdG9KUy54NjQuV29yZC5jcmVhdGUoMHgwMDAxMDIwMywgMHgwNDA1MDYwNyksXG5cdCAgICAgICAgICogICAgICAgICBDcnlwdG9KUy54NjQuV29yZC5jcmVhdGUoMHgxODE5MWExYiwgMHgxYzFkMWUxZilcblx0ICAgICAgICAgKiAgICAgXSk7XG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIHdvcmRBcnJheSA9IENyeXB0b0pTLng2NC5Xb3JkQXJyYXkuY3JlYXRlKFtcblx0ICAgICAgICAgKiAgICAgICAgIENyeXB0b0pTLng2NC5Xb3JkLmNyZWF0ZSgweDAwMDEwMjAzLCAweDA0MDUwNjA3KSxcblx0ICAgICAgICAgKiAgICAgICAgIENyeXB0b0pTLng2NC5Xb3JkLmNyZWF0ZSgweDE4MTkxYTFiLCAweDFjMWQxZTFmKVxuXHQgICAgICAgICAqICAgICBdLCAxMCk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgaW5pdDogZnVuY3Rpb24gKHdvcmRzLCBzaWdCeXRlcykge1xuXHQgICAgICAgICAgICB3b3JkcyA9IHRoaXMud29yZHMgPSB3b3JkcyB8fCBbXTtcblxuXHQgICAgICAgICAgICBpZiAoc2lnQnl0ZXMgIT0gdW5kZWZpbmVkKSB7XG5cdCAgICAgICAgICAgICAgICB0aGlzLnNpZ0J5dGVzID0gc2lnQnl0ZXM7XG5cdCAgICAgICAgICAgIH0gZWxzZSB7XG5cdCAgICAgICAgICAgICAgICB0aGlzLnNpZ0J5dGVzID0gd29yZHMubGVuZ3RoICogODtcblx0ICAgICAgICAgICAgfVxuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDb252ZXJ0cyB0aGlzIDY0LWJpdCB3b3JkIGFycmF5IHRvIGEgMzItYml0IHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtDcnlwdG9KUy5saWIuV29yZEFycmF5fSBUaGlzIHdvcmQgYXJyYXkncyBkYXRhIGFzIGEgMzItYml0IHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciB4MzJXb3JkQXJyYXkgPSB4NjRXb3JkQXJyYXkudG9YMzIoKTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICB0b1gzMjogZnVuY3Rpb24gKCkge1xuXHQgICAgICAgICAgICAvLyBTaG9ydGN1dHNcblx0ICAgICAgICAgICAgdmFyIHg2NFdvcmRzID0gdGhpcy53b3Jkcztcblx0ICAgICAgICAgICAgdmFyIHg2NFdvcmRzTGVuZ3RoID0geDY0V29yZHMubGVuZ3RoO1xuXG5cdCAgICAgICAgICAgIC8vIENvbnZlcnRcblx0ICAgICAgICAgICAgdmFyIHgzMldvcmRzID0gW107XG5cdCAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgeDY0V29yZHNMZW5ndGg7IGkrKykge1xuXHQgICAgICAgICAgICAgICAgdmFyIHg2NFdvcmQgPSB4NjRXb3Jkc1tpXTtcblx0ICAgICAgICAgICAgICAgIHgzMldvcmRzLnB1c2goeDY0V29yZC5oaWdoKTtcblx0ICAgICAgICAgICAgICAgIHgzMldvcmRzLnB1c2goeDY0V29yZC5sb3cpO1xuXHQgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgcmV0dXJuIFgzMldvcmRBcnJheS5jcmVhdGUoeDMyV29yZHMsIHRoaXMuc2lnQnl0ZXMpO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDcmVhdGVzIGEgY29weSBvZiB0aGlzIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtYNjRXb3JkQXJyYXl9IFRoZSBjbG9uZS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIGNsb25lID0geDY0V29yZEFycmF5LmNsb25lKCk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgY2xvbmU6IGZ1bmN0aW9uICgpIHtcblx0ICAgICAgICAgICAgdmFyIGNsb25lID0gQmFzZS5jbG9uZS5jYWxsKHRoaXMpO1xuXG5cdCAgICAgICAgICAgIC8vIENsb25lIFwid29yZHNcIiBhcnJheVxuXHQgICAgICAgICAgICB2YXIgd29yZHMgPSBjbG9uZS53b3JkcyA9IHRoaXMud29yZHMuc2xpY2UoMCk7XG5cblx0ICAgICAgICAgICAgLy8gQ2xvbmUgZWFjaCBYNjRXb3JkIG9iamVjdFxuXHQgICAgICAgICAgICB2YXIgd29yZHNMZW5ndGggPSB3b3Jkcy5sZW5ndGg7XG5cdCAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgd29yZHNMZW5ndGg7IGkrKykge1xuXHQgICAgICAgICAgICAgICAgd29yZHNbaV0gPSB3b3Jkc1tpXS5jbG9uZSgpO1xuXHQgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgcmV0dXJuIGNsb25lO1xuXHQgICAgICAgIH1cblx0ICAgIH0pO1xuXHR9KCkpO1xuXG5cblx0cmV0dXJuIENyeXB0b0pTO1xuXG59KSk7IiwiLyohIGJpZ251bWJlci5qcyB2Mi4wLjcgaHR0cHM6Ly9naXRodWIuY29tL01pa2VNY2wvYmlnbnVtYmVyLmpzL0xJQ0VOQ0UgKi9cblxuOyhmdW5jdGlvbiAoZ2xvYmFsKSB7XG4gICAgJ3VzZSBzdHJpY3QnO1xuXG4gICAgLypcbiAgICAgIGJpZ251bWJlci5qcyB2Mi4wLjdcbiAgICAgIEEgSmF2YVNjcmlwdCBsaWJyYXJ5IGZvciBhcmJpdHJhcnktcHJlY2lzaW9uIGFyaXRobWV0aWMuXG4gICAgICBodHRwczovL2dpdGh1Yi5jb20vTWlrZU1jbC9iaWdudW1iZXIuanNcbiAgICAgIENvcHlyaWdodCAoYykgMjAxNSBNaWNoYWVsIE1jbGF1Z2hsaW4gPE04Y2g4OGxAZ21haWwuY29tPlxuICAgICAgTUlUIEV4cGF0IExpY2VuY2VcbiAgICAqL1xuXG5cbiAgICB2YXIgQmlnTnVtYmVyLCBjcnlwdG8sIHBhcnNlTnVtZXJpYyxcbiAgICAgICAgaXNOdW1lcmljID0gL14tPyhcXGQrKFxcLlxcZCopP3xcXC5cXGQrKShlWystXT9cXGQrKT8kL2ksXG4gICAgICAgIG1hdGhjZWlsID0gTWF0aC5jZWlsLFxuICAgICAgICBtYXRoZmxvb3IgPSBNYXRoLmZsb29yLFxuICAgICAgICBub3RCb29sID0gJyBub3QgYSBib29sZWFuIG9yIGJpbmFyeSBkaWdpdCcsXG4gICAgICAgIHJvdW5kaW5nTW9kZSA9ICdyb3VuZGluZyBtb2RlJyxcbiAgICAgICAgdG9vTWFueURpZ2l0cyA9ICdudW1iZXIgdHlwZSBoYXMgbW9yZSB0aGFuIDE1IHNpZ25pZmljYW50IGRpZ2l0cycsXG4gICAgICAgIEFMUEhBQkVUID0gJzAxMjM0NTY3ODlhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaJF8nLFxuICAgICAgICBCQVNFID0gMWUxNCxcbiAgICAgICAgTE9HX0JBU0UgPSAxNCxcbiAgICAgICAgTUFYX1NBRkVfSU5URUdFUiA9IDB4MWZmZmZmZmZmZmZmZmYsICAgICAgICAgLy8gMl41MyAtIDFcbiAgICAgICAgLy8gTUFYX0lOVDMyID0gMHg3ZmZmZmZmZiwgICAgICAgICAgICAgICAgICAgLy8gMl4zMSAtIDFcbiAgICAgICAgUE9XU19URU4gPSBbMSwgMTAsIDEwMCwgMWUzLCAxZTQsIDFlNSwgMWU2LCAxZTcsIDFlOCwgMWU5LCAxZTEwLCAxZTExLCAxZTEyLCAxZTEzXSxcbiAgICAgICAgU1FSVF9CQVNFID0gMWU3LFxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFRoZSBsaW1pdCBvbiB0aGUgdmFsdWUgb2YgREVDSU1BTF9QTEFDRVMsIFRPX0VYUF9ORUcsIFRPX0VYUF9QT1MsIE1JTl9FWFAsIE1BWF9FWFAsIGFuZFxuICAgICAgICAgKiB0aGUgYXJndW1lbnRzIHRvIHRvRXhwb25lbnRpYWwsIHRvRml4ZWQsIHRvRm9ybWF0LCBhbmQgdG9QcmVjaXNpb24sIGJleW9uZCB3aGljaCBhblxuICAgICAgICAgKiBleGNlcHRpb24gaXMgdGhyb3duIChpZiBFUlJPUlMgaXMgdHJ1ZSkuXG4gICAgICAgICAqL1xuICAgICAgICBNQVggPSAxRTk7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyAwIHRvIE1BWF9JTlQzMlxuXG5cbiAgICAvKlxuICAgICAqIENyZWF0ZSBhbmQgcmV0dXJuIGEgQmlnTnVtYmVyIGNvbnN0cnVjdG9yLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGFub3RoZXIoY29uZmlnT2JqKSB7XG4gICAgICAgIHZhciBkaXYsXG5cbiAgICAgICAgICAgIC8vIGlkIHRyYWNrcyB0aGUgY2FsbGVyIGZ1bmN0aW9uLCBzbyBpdHMgbmFtZSBjYW4gYmUgaW5jbHVkZWQgaW4gZXJyb3IgbWVzc2FnZXMuXG4gICAgICAgICAgICBpZCA9IDAsXG4gICAgICAgICAgICBQID0gQmlnTnVtYmVyLnByb3RvdHlwZSxcbiAgICAgICAgICAgIE9ORSA9IG5ldyBCaWdOdW1iZXIoMSksXG5cblxuICAgICAgICAgICAgLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiBFRElUQUJMRSBERUZBVUxUUyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5cbiAgICAgICAgICAgIC8qXG4gICAgICAgICAgICAgKiBUaGUgZGVmYXVsdCB2YWx1ZXMgYmVsb3cgbXVzdCBiZSBpbnRlZ2VycyB3aXRoaW4gdGhlIGluY2x1c2l2ZSByYW5nZXMgc3RhdGVkLlxuICAgICAgICAgICAgICogVGhlIHZhbHVlcyBjYW4gYWxzbyBiZSBjaGFuZ2VkIGF0IHJ1bi10aW1lIHVzaW5nIEJpZ051bWJlci5jb25maWcuXG4gICAgICAgICAgICAgKi9cblxuICAgICAgICAgICAgLy8gVGhlIG1heGltdW0gbnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzIGZvciBvcGVyYXRpb25zIGludm9sdmluZyBkaXZpc2lvbi5cbiAgICAgICAgICAgIERFQ0lNQUxfUExBQ0VTID0gMjAsICAgICAgICAgICAgICAgICAgICAgLy8gMCB0byBNQVhcblxuICAgICAgICAgICAgLypcbiAgICAgICAgICAgICAqIFRoZSByb3VuZGluZyBtb2RlIHVzZWQgd2hlbiByb3VuZGluZyB0byB0aGUgYWJvdmUgZGVjaW1hbCBwbGFjZXMsIGFuZCB3aGVuIHVzaW5nXG4gICAgICAgICAgICAgKiB0b0V4cG9uZW50aWFsLCB0b0ZpeGVkLCB0b0Zvcm1hdCBhbmQgdG9QcmVjaXNpb24sIGFuZCByb3VuZCAoZGVmYXVsdCB2YWx1ZSkuXG4gICAgICAgICAgICAgKiBVUCAgICAgICAgIDAgQXdheSBmcm9tIHplcm8uXG4gICAgICAgICAgICAgKiBET1dOICAgICAgIDEgVG93YXJkcyB6ZXJvLlxuICAgICAgICAgICAgICogQ0VJTCAgICAgICAyIFRvd2FyZHMgK0luZmluaXR5LlxuICAgICAgICAgICAgICogRkxPT1IgICAgICAzIFRvd2FyZHMgLUluZmluaXR5LlxuICAgICAgICAgICAgICogSEFMRl9VUCAgICA0IFRvd2FyZHMgbmVhcmVzdCBuZWlnaGJvdXIuIElmIGVxdWlkaXN0YW50LCB1cC5cbiAgICAgICAgICAgICAqIEhBTEZfRE9XTiAgNSBUb3dhcmRzIG5lYXJlc3QgbmVpZ2hib3VyLiBJZiBlcXVpZGlzdGFudCwgZG93bi5cbiAgICAgICAgICAgICAqIEhBTEZfRVZFTiAgNiBUb3dhcmRzIG5lYXJlc3QgbmVpZ2hib3VyLiBJZiBlcXVpZGlzdGFudCwgdG93YXJkcyBldmVuIG5laWdoYm91ci5cbiAgICAgICAgICAgICAqIEhBTEZfQ0VJTCAgNyBUb3dhcmRzIG5lYXJlc3QgbmVpZ2hib3VyLiBJZiBlcXVpZGlzdGFudCwgdG93YXJkcyArSW5maW5pdHkuXG4gICAgICAgICAgICAgKiBIQUxGX0ZMT09SIDggVG93YXJkcyBuZWFyZXN0IG5laWdoYm91ci4gSWYgZXF1aWRpc3RhbnQsIHRvd2FyZHMgLUluZmluaXR5LlxuICAgICAgICAgICAgICovXG4gICAgICAgICAgICBST1VORElOR19NT0RFID0gNCwgICAgICAgICAgICAgICAgICAgICAgIC8vIDAgdG8gOFxuXG4gICAgICAgICAgICAvLyBFWFBPTkVOVElBTF9BVCA6IFtUT19FWFBfTkVHICwgVE9fRVhQX1BPU11cblxuICAgICAgICAgICAgLy8gVGhlIGV4cG9uZW50IHZhbHVlIGF0IGFuZCBiZW5lYXRoIHdoaWNoIHRvU3RyaW5nIHJldHVybnMgZXhwb25lbnRpYWwgbm90YXRpb24uXG4gICAgICAgICAgICAvLyBOdW1iZXIgdHlwZTogLTdcbiAgICAgICAgICAgIFRPX0VYUF9ORUcgPSAtNywgICAgICAgICAgICAgICAgICAgICAgICAgLy8gMCB0byAtTUFYXG5cbiAgICAgICAgICAgIC8vIFRoZSBleHBvbmVudCB2YWx1ZSBhdCBhbmQgYWJvdmUgd2hpY2ggdG9TdHJpbmcgcmV0dXJucyBleHBvbmVudGlhbCBub3RhdGlvbi5cbiAgICAgICAgICAgIC8vIE51bWJlciB0eXBlOiAyMVxuICAgICAgICAgICAgVE9fRVhQX1BPUyA9IDIxLCAgICAgICAgICAgICAgICAgICAgICAgICAvLyAwIHRvIE1BWFxuXG4gICAgICAgICAgICAvLyBSQU5HRSA6IFtNSU5fRVhQLCBNQVhfRVhQXVxuXG4gICAgICAgICAgICAvLyBUaGUgbWluaW11bSBleHBvbmVudCB2YWx1ZSwgYmVuZWF0aCB3aGljaCB1bmRlcmZsb3cgdG8gemVybyBvY2N1cnMuXG4gICAgICAgICAgICAvLyBOdW1iZXIgdHlwZTogLTMyNCAgKDVlLTMyNClcbiAgICAgICAgICAgIE1JTl9FWFAgPSAtMWU3LCAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gLTEgdG8gLU1BWFxuXG4gICAgICAgICAgICAvLyBUaGUgbWF4aW11bSBleHBvbmVudCB2YWx1ZSwgYWJvdmUgd2hpY2ggb3ZlcmZsb3cgdG8gSW5maW5pdHkgb2NjdXJzLlxuICAgICAgICAgICAgLy8gTnVtYmVyIHR5cGU6ICAzMDggICgxLjc5NzY5MzEzNDg2MjMxNTdlKzMwOClcbiAgICAgICAgICAgIC8vIEZvciBNQVhfRVhQID4gMWU3LCBlLmcuIG5ldyBCaWdOdW1iZXIoJzFlMTAwMDAwMDAwJykucGx1cygxKSBtYXkgYmUgc2xvdy5cbiAgICAgICAgICAgIE1BWF9FWFAgPSAxZTcsICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gMSB0byBNQVhcblxuICAgICAgICAgICAgLy8gV2hldGhlciBCaWdOdW1iZXIgRXJyb3JzIGFyZSBldmVyIHRocm93bi5cbiAgICAgICAgICAgIEVSUk9SUyA9IHRydWUsICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdHJ1ZSBvciBmYWxzZVxuXG4gICAgICAgICAgICAvLyBDaGFuZ2UgdG8gaW50VmFsaWRhdG9yTm9FcnJvcnMgaWYgRVJST1JTIGlzIGZhbHNlLlxuICAgICAgICAgICAgaXNWYWxpZEludCA9IGludFZhbGlkYXRvcldpdGhFcnJvcnMsICAgICAvLyBpbnRWYWxpZGF0b3JXaXRoRXJyb3JzL2ludFZhbGlkYXRvck5vRXJyb3JzXG5cbiAgICAgICAgICAgIC8vIFdoZXRoZXIgdG8gdXNlIGNyeXB0b2dyYXBoaWNhbGx5LXNlY3VyZSByYW5kb20gbnVtYmVyIGdlbmVyYXRpb24sIGlmIGF2YWlsYWJsZS5cbiAgICAgICAgICAgIENSWVBUTyA9IGZhbHNlLCAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdHJ1ZSBvciBmYWxzZVxuXG4gICAgICAgICAgICAvKlxuICAgICAgICAgICAgICogVGhlIG1vZHVsbyBtb2RlIHVzZWQgd2hlbiBjYWxjdWxhdGluZyB0aGUgbW9kdWx1czogYSBtb2Qgbi5cbiAgICAgICAgICAgICAqIFRoZSBxdW90aWVudCAocSA9IGEgLyBuKSBpcyBjYWxjdWxhdGVkIGFjY29yZGluZyB0byB0aGUgY29ycmVzcG9uZGluZyByb3VuZGluZyBtb2RlLlxuICAgICAgICAgICAgICogVGhlIHJlbWFpbmRlciAocikgaXMgY2FsY3VsYXRlZCBhczogciA9IGEgLSBuICogcS5cbiAgICAgICAgICAgICAqXG4gICAgICAgICAgICAgKiBVUCAgICAgICAgMCBUaGUgcmVtYWluZGVyIGlzIHBvc2l0aXZlIGlmIHRoZSBkaXZpZGVuZCBpcyBuZWdhdGl2ZSwgZWxzZSBpcyBuZWdhdGl2ZS5cbiAgICAgICAgICAgICAqIERPV04gICAgICAxIFRoZSByZW1haW5kZXIgaGFzIHRoZSBzYW1lIHNpZ24gYXMgdGhlIGRpdmlkZW5kLlxuICAgICAgICAgICAgICogICAgICAgICAgICAgVGhpcyBtb2R1bG8gbW9kZSBpcyBjb21tb25seSBrbm93biBhcyAndHJ1bmNhdGVkIGRpdmlzaW9uJyBhbmQgaXNcbiAgICAgICAgICAgICAqICAgICAgICAgICAgIGVxdWl2YWxlbnQgdG8gKGEgJSBuKSBpbiBKYXZhU2NyaXB0LlxuICAgICAgICAgICAgICogRkxPT1IgICAgIDMgVGhlIHJlbWFpbmRlciBoYXMgdGhlIHNhbWUgc2lnbiBhcyB0aGUgZGl2aXNvciAoUHl0aG9uICUpLlxuICAgICAgICAgICAgICogSEFMRl9FVkVOIDYgVGhpcyBtb2R1bG8gbW9kZSBpbXBsZW1lbnRzIHRoZSBJRUVFIDc1NCByZW1haW5kZXIgZnVuY3Rpb24uXG4gICAgICAgICAgICAgKiBFVUNMSUQgICAgOSBFdWNsaWRpYW4gZGl2aXNpb24uIHEgPSBzaWduKG4pICogZmxvb3IoYSAvIGFicyhuKSkuXG4gICAgICAgICAgICAgKiAgICAgICAgICAgICBUaGUgcmVtYWluZGVyIGlzIGFsd2F5cyBwb3NpdGl2ZS5cbiAgICAgICAgICAgICAqXG4gICAgICAgICAgICAgKiBUaGUgdHJ1bmNhdGVkIGRpdmlzaW9uLCBmbG9vcmVkIGRpdmlzaW9uLCBFdWNsaWRpYW4gZGl2aXNpb24gYW5kIElFRUUgNzU0IHJlbWFpbmRlclxuICAgICAgICAgICAgICogbW9kZXMgYXJlIGNvbW1vbmx5IHVzZWQgZm9yIHRoZSBtb2R1bHVzIG9wZXJhdGlvbi5cbiAgICAgICAgICAgICAqIEFsdGhvdWdoIHRoZSBvdGhlciByb3VuZGluZyBtb2RlcyBjYW4gYWxzbyBiZSB1c2VkLCB0aGV5IG1heSBub3QgZ2l2ZSB1c2VmdWwgcmVzdWx0cy5cbiAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgTU9EVUxPX01PREUgPSAxLCAgICAgICAgICAgICAgICAgICAgICAgICAvLyAwIHRvIDlcblxuICAgICAgICAgICAgLy8gVGhlIG1heGltdW0gbnVtYmVyIG9mIHNpZ25pZmljYW50IGRpZ2l0cyBvZiB0aGUgcmVzdWx0IG9mIHRoZSB0b1Bvd2VyIG9wZXJhdGlvbi5cbiAgICAgICAgICAgIC8vIElmIFBPV19QUkVDSVNJT04gaXMgMCwgdGhlcmUgd2lsbCBiZSB1bmxpbWl0ZWQgc2lnbmlmaWNhbnQgZGlnaXRzLlxuICAgICAgICAgICAgUE9XX1BSRUNJU0lPTiA9IDEwMCwgICAgICAgICAgICAgICAgICAgICAvLyAwIHRvIE1BWFxuXG4gICAgICAgICAgICAvLyBUaGUgZm9ybWF0IHNwZWNpZmljYXRpb24gdXNlZCBieSB0aGUgQmlnTnVtYmVyLnByb3RvdHlwZS50b0Zvcm1hdCBtZXRob2QuXG4gICAgICAgICAgICBGT1JNQVQgPSB7XG4gICAgICAgICAgICAgICAgZGVjaW1hbFNlcGFyYXRvcjogJy4nLFxuICAgICAgICAgICAgICAgIGdyb3VwU2VwYXJhdG9yOiAnLCcsXG4gICAgICAgICAgICAgICAgZ3JvdXBTaXplOiAzLFxuICAgICAgICAgICAgICAgIHNlY29uZGFyeUdyb3VwU2l6ZTogMCxcbiAgICAgICAgICAgICAgICBmcmFjdGlvbkdyb3VwU2VwYXJhdG9yOiAnXFx4QTAnLCAgICAgIC8vIG5vbi1icmVha2luZyBzcGFjZVxuICAgICAgICAgICAgICAgIGZyYWN0aW9uR3JvdXBTaXplOiAwXG4gICAgICAgICAgICB9O1xuXG5cbiAgICAgICAgLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuXG4gICAgICAgIC8vIENPTlNUUlVDVE9SXG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBUaGUgQmlnTnVtYmVyIGNvbnN0cnVjdG9yIGFuZCBleHBvcnRlZCBmdW5jdGlvbi5cbiAgICAgICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBuZXcgaW5zdGFuY2Ugb2YgYSBCaWdOdW1iZXIgb2JqZWN0LlxuICAgICAgICAgKlxuICAgICAgICAgKiBuIHtudW1iZXJ8c3RyaW5nfEJpZ051bWJlcn0gQSBudW1lcmljIHZhbHVlLlxuICAgICAgICAgKiBbYl0ge251bWJlcn0gVGhlIGJhc2Ugb2Ygbi4gSW50ZWdlciwgMiB0byA2NCBpbmNsdXNpdmUuXG4gICAgICAgICAqL1xuICAgICAgICBmdW5jdGlvbiBCaWdOdW1iZXIoIG4sIGIgKSB7XG4gICAgICAgICAgICB2YXIgYywgZSwgaSwgbnVtLCBsZW4sIHN0cixcbiAgICAgICAgICAgICAgICB4ID0gdGhpcztcblxuICAgICAgICAgICAgLy8gRW5hYmxlIGNvbnN0cnVjdG9yIHVzYWdlIHdpdGhvdXQgbmV3LlxuICAgICAgICAgICAgaWYgKCAhKCB4IGluc3RhbmNlb2YgQmlnTnVtYmVyICkgKSB7XG5cbiAgICAgICAgICAgICAgICAvLyAnQmlnTnVtYmVyKCkgY29uc3RydWN0b3IgY2FsbCB3aXRob3V0IG5ldzoge259J1xuICAgICAgICAgICAgICAgIGlmIChFUlJPUlMpIHJhaXNlKCAyNiwgJ2NvbnN0cnVjdG9yIGNhbGwgd2l0aG91dCBuZXcnLCBuICk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBCaWdOdW1iZXIoIG4sIGIgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gJ25ldyBCaWdOdW1iZXIoKSBiYXNlIG5vdCBhbiBpbnRlZ2VyOiB7Yn0nXG4gICAgICAgICAgICAvLyAnbmV3IEJpZ051bWJlcigpIGJhc2Ugb3V0IG9mIHJhbmdlOiB7Yn0nXG4gICAgICAgICAgICBpZiAoIGIgPT0gbnVsbCB8fCAhaXNWYWxpZEludCggYiwgMiwgNjQsIGlkLCAnYmFzZScgKSApIHtcblxuICAgICAgICAgICAgICAgIC8vIER1cGxpY2F0ZS5cbiAgICAgICAgICAgICAgICBpZiAoIG4gaW5zdGFuY2VvZiBCaWdOdW1iZXIgKSB7XG4gICAgICAgICAgICAgICAgICAgIHgucyA9IG4ucztcbiAgICAgICAgICAgICAgICAgICAgeC5lID0gbi5lO1xuICAgICAgICAgICAgICAgICAgICB4LmMgPSAoIG4gPSBuLmMgKSA/IG4uc2xpY2UoKSA6IG47XG4gICAgICAgICAgICAgICAgICAgIGlkID0gMDtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICggKCBudW0gPSB0eXBlb2YgbiA9PSAnbnVtYmVyJyApICYmIG4gKiAwID09IDAgKSB7XG4gICAgICAgICAgICAgICAgICAgIHgucyA9IDEgLyBuIDwgMCA/ICggbiA9IC1uLCAtMSApIDogMTtcblxuICAgICAgICAgICAgICAgICAgICAvLyBGYXN0IHBhdGggZm9yIGludGVnZXJzLlxuICAgICAgICAgICAgICAgICAgICBpZiAoIG4gPT09IH5+biApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoIGUgPSAwLCBpID0gbjsgaSA+PSAxMDsgaSAvPSAxMCwgZSsrICk7XG4gICAgICAgICAgICAgICAgICAgICAgICB4LmUgPSBlO1xuICAgICAgICAgICAgICAgICAgICAgICAgeC5jID0gW25dO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWQgPSAwO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgc3RyID0gbiArICcnO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICggIWlzTnVtZXJpYy50ZXN0KCBzdHIgPSBuICsgJycgKSApIHJldHVybiBwYXJzZU51bWVyaWMoIHgsIHN0ciwgbnVtICk7XG4gICAgICAgICAgICAgICAgICAgIHgucyA9IHN0ci5jaGFyQ29kZUF0KDApID09PSA0NSA/ICggc3RyID0gc3RyLnNsaWNlKDEpLCAtMSApIDogMTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGIgPSBiIHwgMDtcbiAgICAgICAgICAgICAgICBzdHIgPSBuICsgJyc7XG5cbiAgICAgICAgICAgICAgICAvLyBFbnN1cmUgcmV0dXJuIHZhbHVlIGlzIHJvdW5kZWQgdG8gREVDSU1BTF9QTEFDRVMgYXMgd2l0aCBvdGhlciBiYXNlcy5cbiAgICAgICAgICAgICAgICAvLyBBbGxvdyBleHBvbmVudGlhbCBub3RhdGlvbiB0byBiZSB1c2VkIHdpdGggYmFzZSAxMCBhcmd1bWVudC5cbiAgICAgICAgICAgICAgICBpZiAoIGIgPT0gMTAgKSB7XG4gICAgICAgICAgICAgICAgICAgIHggPSBuZXcgQmlnTnVtYmVyKCBuIGluc3RhbmNlb2YgQmlnTnVtYmVyID8gbiA6IHN0ciApO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gcm91bmQoIHgsIERFQ0lNQUxfUExBQ0VTICsgeC5lICsgMSwgUk9VTkRJTkdfTU9ERSApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIEF2b2lkIHBvdGVudGlhbCBpbnRlcnByZXRhdGlvbiBvZiBJbmZpbml0eSBhbmQgTmFOIGFzIGJhc2UgNDQrIHZhbHVlcy5cbiAgICAgICAgICAgICAgICAvLyBBbnkgbnVtYmVyIGluIGV4cG9uZW50aWFsIGZvcm0gd2lsbCBmYWlsIGR1ZSB0byB0aGUgW0VlXVsrLV0uXG4gICAgICAgICAgICAgICAgaWYgKCAoIG51bSA9IHR5cGVvZiBuID09ICdudW1iZXInICkgJiYgbiAqIDAgIT0gMCB8fFxuICAgICAgICAgICAgICAgICAgISggbmV3IFJlZ0V4cCggJ14tPycgKyAoIGMgPSAnWycgKyBBTFBIQUJFVC5zbGljZSggMCwgYiApICsgJ10rJyApICtcbiAgICAgICAgICAgICAgICAgICAgJyg/OlxcXFwuJyArIGMgKyAnKT8kJyxiIDwgMzcgPyAnaScgOiAnJyApICkudGVzdChzdHIpICkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gcGFyc2VOdW1lcmljKCB4LCBzdHIsIG51bSwgYiApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmIChudW0pIHtcbiAgICAgICAgICAgICAgICAgICAgeC5zID0gMSAvIG4gPCAwID8gKCBzdHIgPSBzdHIuc2xpY2UoMSksIC0xICkgOiAxO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmICggRVJST1JTICYmIHN0ci5yZXBsYWNlKCAvXjBcXC4wKnxcXC4vLCAnJyApLmxlbmd0aCA+IDE1ICkge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAnbmV3IEJpZ051bWJlcigpIG51bWJlciB0eXBlIGhhcyBtb3JlIHRoYW4gMTUgc2lnbmlmaWNhbnQgZGlnaXRzOiB7bn0nXG4gICAgICAgICAgICAgICAgICAgICAgICByYWlzZSggaWQsIHRvb01hbnlEaWdpdHMsIG4gKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIFByZXZlbnQgbGF0ZXIgY2hlY2sgZm9yIGxlbmd0aCBvbiBjb252ZXJ0ZWQgbnVtYmVyLlxuICAgICAgICAgICAgICAgICAgICBudW0gPSBmYWxzZTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB4LnMgPSBzdHIuY2hhckNvZGVBdCgwKSA9PT0gNDUgPyAoIHN0ciA9IHN0ci5zbGljZSgxKSwgLTEgKSA6IDE7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgc3RyID0gY29udmVydEJhc2UoIHN0ciwgMTAsIGIsIHgucyApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBEZWNpbWFsIHBvaW50P1xuICAgICAgICAgICAgaWYgKCAoIGUgPSBzdHIuaW5kZXhPZignLicpICkgPiAtMSApIHN0ciA9IHN0ci5yZXBsYWNlKCAnLicsICcnICk7XG5cbiAgICAgICAgICAgIC8vIEV4cG9uZW50aWFsIGZvcm0/XG4gICAgICAgICAgICBpZiAoICggaSA9IHN0ci5zZWFyY2goIC9lL2kgKSApID4gMCApIHtcblxuICAgICAgICAgICAgICAgIC8vIERldGVybWluZSBleHBvbmVudC5cbiAgICAgICAgICAgICAgICBpZiAoIGUgPCAwICkgZSA9IGk7XG4gICAgICAgICAgICAgICAgZSArPSArc3RyLnNsaWNlKCBpICsgMSApO1xuICAgICAgICAgICAgICAgIHN0ciA9IHN0ci5zdWJzdHJpbmcoIDAsIGkgKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoIGUgPCAwICkge1xuXG4gICAgICAgICAgICAgICAgLy8gSW50ZWdlci5cbiAgICAgICAgICAgICAgICBlID0gc3RyLmxlbmd0aDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gRGV0ZXJtaW5lIGxlYWRpbmcgemVyb3MuXG4gICAgICAgICAgICBmb3IgKCBpID0gMDsgc3RyLmNoYXJDb2RlQXQoaSkgPT09IDQ4OyBpKysgKTtcblxuICAgICAgICAgICAgLy8gRGV0ZXJtaW5lIHRyYWlsaW5nIHplcm9zLlxuICAgICAgICAgICAgZm9yICggbGVuID0gc3RyLmxlbmd0aDsgc3RyLmNoYXJDb2RlQXQoLS1sZW4pID09PSA0ODsgKTtcbiAgICAgICAgICAgIHN0ciA9IHN0ci5zbGljZSggaSwgbGVuICsgMSApO1xuXG4gICAgICAgICAgICBpZiAoc3RyKSB7XG4gICAgICAgICAgICAgICAgbGVuID0gc3RyLmxlbmd0aDtcblxuICAgICAgICAgICAgICAgIC8vIERpc2FsbG93IG51bWJlcnMgd2l0aCBvdmVyIDE1IHNpZ25pZmljYW50IGRpZ2l0cyBpZiBudW1iZXIgdHlwZS5cbiAgICAgICAgICAgICAgICAvLyAnbmV3IEJpZ051bWJlcigpIG51bWJlciB0eXBlIGhhcyBtb3JlIHRoYW4gMTUgc2lnbmlmaWNhbnQgZGlnaXRzOiB7bn0nXG4gICAgICAgICAgICAgICAgaWYgKCBudW0gJiYgRVJST1JTICYmIGxlbiA+IDE1ICkgcmFpc2UoIGlkLCB0b29NYW55RGlnaXRzLCB4LnMgKiBuICk7XG5cbiAgICAgICAgICAgICAgICBlID0gZSAtIGkgLSAxO1xuXG4gICAgICAgICAgICAgICAgIC8vIE92ZXJmbG93P1xuICAgICAgICAgICAgICAgIGlmICggZSA+IE1BWF9FWFAgKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gSW5maW5pdHkuXG4gICAgICAgICAgICAgICAgICAgIHguYyA9IHguZSA9IG51bGw7XG5cbiAgICAgICAgICAgICAgICAvLyBVbmRlcmZsb3c/XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmICggZSA8IE1JTl9FWFAgKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gWmVyby5cbiAgICAgICAgICAgICAgICAgICAgeC5jID0gWyB4LmUgPSAwIF07XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgeC5lID0gZTtcbiAgICAgICAgICAgICAgICAgICAgeC5jID0gW107XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gVHJhbnNmb3JtIGJhc2VcblxuICAgICAgICAgICAgICAgICAgICAvLyBlIGlzIHRoZSBiYXNlIDEwIGV4cG9uZW50LlxuICAgICAgICAgICAgICAgICAgICAvLyBpIGlzIHdoZXJlIHRvIHNsaWNlIHN0ciB0byBnZXQgdGhlIGZpcnN0IGVsZW1lbnQgb2YgdGhlIGNvZWZmaWNpZW50IGFycmF5LlxuICAgICAgICAgICAgICAgICAgICBpID0gKCBlICsgMSApICUgTE9HX0JBU0U7XG4gICAgICAgICAgICAgICAgICAgIGlmICggZSA8IDAgKSBpICs9IExPR19CQVNFO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmICggaSA8IGxlbiApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpKSB4LmMucHVzaCggK3N0ci5zbGljZSggMCwgaSApICk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoIGxlbiAtPSBMT0dfQkFTRTsgaSA8IGxlbjsgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgeC5jLnB1c2goICtzdHIuc2xpY2UoIGksIGkgKz0gTE9HX0JBU0UgKSApO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICBzdHIgPSBzdHIuc2xpY2UoaSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpID0gTE9HX0JBU0UgLSBzdHIubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgaSAtPSBsZW47XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBmb3IgKCA7IGktLTsgc3RyICs9ICcwJyApO1xuICAgICAgICAgICAgICAgICAgICB4LmMucHVzaCggK3N0ciApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG5cbiAgICAgICAgICAgICAgICAvLyBaZXJvLlxuICAgICAgICAgICAgICAgIHguYyA9IFsgeC5lID0gMCBdO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZCA9IDA7XG4gICAgICAgIH1cblxuXG4gICAgICAgIC8vIENPTlNUUlVDVE9SIFBST1BFUlRJRVNcblxuXG4gICAgICAgIEJpZ051bWJlci5hbm90aGVyID0gYW5vdGhlcjtcblxuICAgICAgICBCaWdOdW1iZXIuUk9VTkRfVVAgPSAwO1xuICAgICAgICBCaWdOdW1iZXIuUk9VTkRfRE9XTiA9IDE7XG4gICAgICAgIEJpZ051bWJlci5ST1VORF9DRUlMID0gMjtcbiAgICAgICAgQmlnTnVtYmVyLlJPVU5EX0ZMT09SID0gMztcbiAgICAgICAgQmlnTnVtYmVyLlJPVU5EX0hBTEZfVVAgPSA0O1xuICAgICAgICBCaWdOdW1iZXIuUk9VTkRfSEFMRl9ET1dOID0gNTtcbiAgICAgICAgQmlnTnVtYmVyLlJPVU5EX0hBTEZfRVZFTiA9IDY7XG4gICAgICAgIEJpZ051bWJlci5ST1VORF9IQUxGX0NFSUwgPSA3O1xuICAgICAgICBCaWdOdW1iZXIuUk9VTkRfSEFMRl9GTE9PUiA9IDg7XG4gICAgICAgIEJpZ051bWJlci5FVUNMSUQgPSA5O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogQ29uZmlndXJlIGluZnJlcXVlbnRseS1jaGFuZ2luZyBsaWJyYXJ5LXdpZGUgc2V0dGluZ3MuXG4gICAgICAgICAqXG4gICAgICAgICAqIEFjY2VwdCBhbiBvYmplY3Qgb3IgYW4gYXJndW1lbnQgbGlzdCwgd2l0aCBvbmUgb3IgbWFueSBvZiB0aGUgZm9sbG93aW5nIHByb3BlcnRpZXMgb3JcbiAgICAgICAgICogcGFyYW1ldGVycyByZXNwZWN0aXZlbHk6XG4gICAgICAgICAqXG4gICAgICAgICAqICAgREVDSU1BTF9QTEFDRVMgIHtudW1iZXJ9ICBJbnRlZ2VyLCAwIHRvIE1BWCBpbmNsdXNpdmVcbiAgICAgICAgICogICBST1VORElOR19NT0RFICAge251bWJlcn0gIEludGVnZXIsIDAgdG8gOCBpbmNsdXNpdmVcbiAgICAgICAgICogICBFWFBPTkVOVElBTF9BVCAge251bWJlcnxudW1iZXJbXX0gIEludGVnZXIsIC1NQVggdG8gTUFYIGluY2x1c2l2ZSBvclxuICAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW2ludGVnZXIgLU1BWCB0byAwIGluY2wuLCAwIHRvIE1BWCBpbmNsLl1cbiAgICAgICAgICogICBSQU5HRSAgICAgICAgICAge251bWJlcnxudW1iZXJbXX0gIE5vbi16ZXJvIGludGVnZXIsIC1NQVggdG8gTUFYIGluY2x1c2l2ZSBvclxuICAgICAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW2ludGVnZXIgLU1BWCB0byAtMSBpbmNsLiwgaW50ZWdlciAxIHRvIE1BWCBpbmNsLl1cbiAgICAgICAgICogICBFUlJPUlMgICAgICAgICAge2Jvb2xlYW58bnVtYmVyfSAgIHRydWUsIGZhbHNlLCAxIG9yIDBcbiAgICAgICAgICogICBDUllQVE8gICAgICAgICAge2Jvb2xlYW58bnVtYmVyfSAgIHRydWUsIGZhbHNlLCAxIG9yIDBcbiAgICAgICAgICogICBNT0RVTE9fTU9ERSAgICAge251bWJlcn0gICAgICAgICAgIDAgdG8gOSBpbmNsdXNpdmVcbiAgICAgICAgICogICBQT1dfUFJFQ0lTSU9OICAge251bWJlcn0gICAgICAgICAgIDAgdG8gTUFYIGluY2x1c2l2ZVxuICAgICAgICAgKiAgIEZPUk1BVCAgICAgICAgICB7b2JqZWN0fSAgICAgICAgICAgU2VlIEJpZ051bWJlci5wcm90b3R5cGUudG9Gb3JtYXRcbiAgICAgICAgICogICAgICBkZWNpbWFsU2VwYXJhdG9yICAgICAgIHtzdHJpbmd9XG4gICAgICAgICAqICAgICAgZ3JvdXBTZXBhcmF0b3IgICAgICAgICB7c3RyaW5nfVxuICAgICAgICAgKiAgICAgIGdyb3VwU2l6ZSAgICAgICAgICAgICAge251bWJlcn1cbiAgICAgICAgICogICAgICBzZWNvbmRhcnlHcm91cFNpemUgICAgIHtudW1iZXJ9XG4gICAgICAgICAqICAgICAgZnJhY3Rpb25Hcm91cFNlcGFyYXRvciB7c3RyaW5nfVxuICAgICAgICAgKiAgICAgIGZyYWN0aW9uR3JvdXBTaXplICAgICAge251bWJlcn1cbiAgICAgICAgICpcbiAgICAgICAgICogKFRoZSB2YWx1ZXMgYXNzaWduZWQgdG8gdGhlIGFib3ZlIEZPUk1BVCBvYmplY3QgcHJvcGVydGllcyBhcmUgbm90IGNoZWNrZWQgZm9yIHZhbGlkaXR5LilcbiAgICAgICAgICpcbiAgICAgICAgICogRS5nLlxuICAgICAgICAgKiBCaWdOdW1iZXIuY29uZmlnKDIwLCA0KSBpcyBlcXVpdmFsZW50IHRvXG4gICAgICAgICAqIEJpZ051bWJlci5jb25maWcoeyBERUNJTUFMX1BMQUNFUyA6IDIwLCBST1VORElOR19NT0RFIDogNCB9KVxuICAgICAgICAgKlxuICAgICAgICAgKiBJZ25vcmUgcHJvcGVydGllcy9wYXJhbWV0ZXJzIHNldCB0byBudWxsIG9yIHVuZGVmaW5lZC5cbiAgICAgICAgICogUmV0dXJuIGFuIG9iamVjdCB3aXRoIHRoZSBwcm9wZXJ0aWVzIGN1cnJlbnQgdmFsdWVzLlxuICAgICAgICAgKi9cbiAgICAgICAgQmlnTnVtYmVyLmNvbmZpZyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciB2LCBwLFxuICAgICAgICAgICAgICAgIGkgPSAwLFxuICAgICAgICAgICAgICAgIHIgPSB7fSxcbiAgICAgICAgICAgICAgICBhID0gYXJndW1lbnRzLFxuICAgICAgICAgICAgICAgIG8gPSBhWzBdLFxuICAgICAgICAgICAgICAgIGhhcyA9IG8gJiYgdHlwZW9mIG8gPT0gJ29iamVjdCdcbiAgICAgICAgICAgICAgICAgID8gZnVuY3Rpb24gKCkgeyBpZiAoIG8uaGFzT3duUHJvcGVydHkocCkgKSByZXR1cm4gKCB2ID0gb1twXSApICE9IG51bGw7IH1cbiAgICAgICAgICAgICAgICAgIDogZnVuY3Rpb24gKCkgeyBpZiAoIGEubGVuZ3RoID4gaSApIHJldHVybiAoIHYgPSBhW2krK10gKSAhPSBudWxsOyB9O1xuXG4gICAgICAgICAgICAvLyBERUNJTUFMX1BMQUNFUyB7bnVtYmVyfSBJbnRlZ2VyLCAwIHRvIE1BWCBpbmNsdXNpdmUuXG4gICAgICAgICAgICAvLyAnY29uZmlnKCkgREVDSU1BTF9QTEFDRVMgbm90IGFuIGludGVnZXI6IHt2fSdcbiAgICAgICAgICAgIC8vICdjb25maWcoKSBERUNJTUFMX1BMQUNFUyBvdXQgb2YgcmFuZ2U6IHt2fSdcbiAgICAgICAgICAgIGlmICggaGFzKCBwID0gJ0RFQ0lNQUxfUExBQ0VTJyApICYmIGlzVmFsaWRJbnQoIHYsIDAsIE1BWCwgMiwgcCApICkge1xuICAgICAgICAgICAgICAgIERFQ0lNQUxfUExBQ0VTID0gdiB8IDA7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByW3BdID0gREVDSU1BTF9QTEFDRVM7XG5cbiAgICAgICAgICAgIC8vIFJPVU5ESU5HX01PREUge251bWJlcn0gSW50ZWdlciwgMCB0byA4IGluY2x1c2l2ZS5cbiAgICAgICAgICAgIC8vICdjb25maWcoKSBST1VORElOR19NT0RFIG5vdCBhbiBpbnRlZ2VyOiB7dn0nXG4gICAgICAgICAgICAvLyAnY29uZmlnKCkgUk9VTkRJTkdfTU9ERSBvdXQgb2YgcmFuZ2U6IHt2fSdcbiAgICAgICAgICAgIGlmICggaGFzKCBwID0gJ1JPVU5ESU5HX01PREUnICkgJiYgaXNWYWxpZEludCggdiwgMCwgOCwgMiwgcCApICkge1xuICAgICAgICAgICAgICAgIFJPVU5ESU5HX01PREUgPSB2IHwgMDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJbcF0gPSBST1VORElOR19NT0RFO1xuXG4gICAgICAgICAgICAvLyBFWFBPTkVOVElBTF9BVCB7bnVtYmVyfG51bWJlcltdfVxuICAgICAgICAgICAgLy8gSW50ZWdlciwgLU1BWCB0byBNQVggaW5jbHVzaXZlIG9yIFtpbnRlZ2VyIC1NQVggdG8gMCBpbmNsdXNpdmUsIDAgdG8gTUFYIGluY2x1c2l2ZV0uXG4gICAgICAgICAgICAvLyAnY29uZmlnKCkgRVhQT05FTlRJQUxfQVQgbm90IGFuIGludGVnZXI6IHt2fSdcbiAgICAgICAgICAgIC8vICdjb25maWcoKSBFWFBPTkVOVElBTF9BVCBvdXQgb2YgcmFuZ2U6IHt2fSdcbiAgICAgICAgICAgIGlmICggaGFzKCBwID0gJ0VYUE9ORU5USUFMX0FUJyApICkge1xuXG4gICAgICAgICAgICAgICAgaWYgKCBpc0FycmF5KHYpICkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIGlzVmFsaWRJbnQoIHZbMF0sIC1NQVgsIDAsIDIsIHAgKSAmJiBpc1ZhbGlkSW50KCB2WzFdLCAwLCBNQVgsIDIsIHAgKSApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIFRPX0VYUF9ORUcgPSB2WzBdIHwgMDtcbiAgICAgICAgICAgICAgICAgICAgICAgIFRPX0VYUF9QT1MgPSB2WzFdIHwgMDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoIGlzVmFsaWRJbnQoIHYsIC1NQVgsIE1BWCwgMiwgcCApICkge1xuICAgICAgICAgICAgICAgICAgICBUT19FWFBfTkVHID0gLSggVE9fRVhQX1BPUyA9ICggdiA8IDAgPyAtdiA6IHYgKSB8IDAgKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByW3BdID0gWyBUT19FWFBfTkVHLCBUT19FWFBfUE9TIF07XG5cbiAgICAgICAgICAgIC8vIFJBTkdFIHtudW1iZXJ8bnVtYmVyW119IE5vbi16ZXJvIGludGVnZXIsIC1NQVggdG8gTUFYIGluY2x1c2l2ZSBvclxuICAgICAgICAgICAgLy8gW2ludGVnZXIgLU1BWCB0byAtMSBpbmNsdXNpdmUsIGludGVnZXIgMSB0byBNQVggaW5jbHVzaXZlXS5cbiAgICAgICAgICAgIC8vICdjb25maWcoKSBSQU5HRSBub3QgYW4gaW50ZWdlcjoge3Z9J1xuICAgICAgICAgICAgLy8gJ2NvbmZpZygpIFJBTkdFIGNhbm5vdCBiZSB6ZXJvOiB7dn0nXG4gICAgICAgICAgICAvLyAnY29uZmlnKCkgUkFOR0Ugb3V0IG9mIHJhbmdlOiB7dn0nXG4gICAgICAgICAgICBpZiAoIGhhcyggcCA9ICdSQU5HRScgKSApIHtcblxuICAgICAgICAgICAgICAgIGlmICggaXNBcnJheSh2KSApIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCBpc1ZhbGlkSW50KCB2WzBdLCAtTUFYLCAtMSwgMiwgcCApICYmIGlzVmFsaWRJbnQoIHZbMV0sIDEsIE1BWCwgMiwgcCApICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgTUlOX0VYUCA9IHZbMF0gfCAwO1xuICAgICAgICAgICAgICAgICAgICAgICAgTUFYX0VYUCA9IHZbMV0gfCAwO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmICggaXNWYWxpZEludCggdiwgLU1BWCwgTUFYLCAyLCBwICkgKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICggdiB8IDAgKSBNSU5fRVhQID0gLSggTUFYX0VYUCA9ICggdiA8IDAgPyAtdiA6IHYgKSB8IDAgKTtcbiAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoRVJST1JTKSByYWlzZSggMiwgcCArICcgY2Fubm90IGJlIHplcm8nLCB2ICk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcltwXSA9IFsgTUlOX0VYUCwgTUFYX0VYUCBdO1xuXG4gICAgICAgICAgICAvLyBFUlJPUlMge2Jvb2xlYW58bnVtYmVyfSB0cnVlLCBmYWxzZSwgMSBvciAwLlxuICAgICAgICAgICAgLy8gJ2NvbmZpZygpIEVSUk9SUyBub3QgYSBib29sZWFuIG9yIGJpbmFyeSBkaWdpdDoge3Z9J1xuICAgICAgICAgICAgaWYgKCBoYXMoIHAgPSAnRVJST1JTJyApICkge1xuXG4gICAgICAgICAgICAgICAgaWYgKCB2ID09PSAhIXYgfHwgdiA9PT0gMSB8fCB2ID09PSAwICkge1xuICAgICAgICAgICAgICAgICAgICBpZCA9IDA7XG4gICAgICAgICAgICAgICAgICAgIGlzVmFsaWRJbnQgPSAoIEVSUk9SUyA9ICEhdiApID8gaW50VmFsaWRhdG9yV2l0aEVycm9ycyA6IGludFZhbGlkYXRvck5vRXJyb3JzO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoRVJST1JTKSB7XG4gICAgICAgICAgICAgICAgICAgIHJhaXNlKCAyLCBwICsgbm90Qm9vbCwgdiApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJbcF0gPSBFUlJPUlM7XG5cbiAgICAgICAgICAgIC8vIENSWVBUTyB7Ym9vbGVhbnxudW1iZXJ9IHRydWUsIGZhbHNlLCAxIG9yIDAuXG4gICAgICAgICAgICAvLyAnY29uZmlnKCkgQ1JZUFRPIG5vdCBhIGJvb2xlYW4gb3IgYmluYXJ5IGRpZ2l0OiB7dn0nXG4gICAgICAgICAgICAvLyAnY29uZmlnKCkgY3J5cHRvIHVuYXZhaWxhYmxlOiB7Y3J5cHRvfSdcbiAgICAgICAgICAgIGlmICggaGFzKCBwID0gJ0NSWVBUTycgKSApIHtcblxuICAgICAgICAgICAgICAgIGlmICggdiA9PT0gISF2IHx8IHYgPT09IDEgfHwgdiA9PT0gMCApIHtcbiAgICAgICAgICAgICAgICAgICAgQ1JZUFRPID0gISEoIHYgJiYgY3J5cHRvICYmIHR5cGVvZiBjcnlwdG8gPT0gJ29iamVjdCcgKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCB2ICYmICFDUllQVE8gJiYgRVJST1JTICkgcmFpc2UoIDIsICdjcnlwdG8gdW5hdmFpbGFibGUnLCBjcnlwdG8gKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKEVSUk9SUykge1xuICAgICAgICAgICAgICAgICAgICByYWlzZSggMiwgcCArIG5vdEJvb2wsIHYgKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByW3BdID0gQ1JZUFRPO1xuXG4gICAgICAgICAgICAvLyBNT0RVTE9fTU9ERSB7bnVtYmVyfSBJbnRlZ2VyLCAwIHRvIDkgaW5jbHVzaXZlLlxuICAgICAgICAgICAgLy8gJ2NvbmZpZygpIE1PRFVMT19NT0RFIG5vdCBhbiBpbnRlZ2VyOiB7dn0nXG4gICAgICAgICAgICAvLyAnY29uZmlnKCkgTU9EVUxPX01PREUgb3V0IG9mIHJhbmdlOiB7dn0nXG4gICAgICAgICAgICBpZiAoIGhhcyggcCA9ICdNT0RVTE9fTU9ERScgKSAmJiBpc1ZhbGlkSW50KCB2LCAwLCA5LCAyLCBwICkgKSB7XG4gICAgICAgICAgICAgICAgTU9EVUxPX01PREUgPSB2IHwgMDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJbcF0gPSBNT0RVTE9fTU9ERTtcblxuICAgICAgICAgICAgLy8gUE9XX1BSRUNJU0lPTiB7bnVtYmVyfSBJbnRlZ2VyLCAwIHRvIE1BWCBpbmNsdXNpdmUuXG4gICAgICAgICAgICAvLyAnY29uZmlnKCkgUE9XX1BSRUNJU0lPTiBub3QgYW4gaW50ZWdlcjoge3Z9J1xuICAgICAgICAgICAgLy8gJ2NvbmZpZygpIFBPV19QUkVDSVNJT04gb3V0IG9mIHJhbmdlOiB7dn0nXG4gICAgICAgICAgICBpZiAoIGhhcyggcCA9ICdQT1dfUFJFQ0lTSU9OJyApICYmIGlzVmFsaWRJbnQoIHYsIDAsIE1BWCwgMiwgcCApICkge1xuICAgICAgICAgICAgICAgIFBPV19QUkVDSVNJT04gPSB2IHwgMDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJbcF0gPSBQT1dfUFJFQ0lTSU9OO1xuXG4gICAgICAgICAgICAvLyBGT1JNQVQge29iamVjdH1cbiAgICAgICAgICAgIC8vICdjb25maWcoKSBGT1JNQVQgbm90IGFuIG9iamVjdDoge3Z9J1xuICAgICAgICAgICAgaWYgKCBoYXMoIHAgPSAnRk9STUFUJyApICkge1xuXG4gICAgICAgICAgICAgICAgaWYgKCB0eXBlb2YgdiA9PSAnb2JqZWN0JyApIHtcbiAgICAgICAgICAgICAgICAgICAgRk9STUFUID0gdjtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKEVSUk9SUykge1xuICAgICAgICAgICAgICAgICAgICByYWlzZSggMiwgcCArICcgbm90IGFuIG9iamVjdCcsIHYgKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByW3BdID0gRk9STUFUO1xuXG4gICAgICAgICAgICByZXR1cm4gcjtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiBhIG5ldyBCaWdOdW1iZXIgd2hvc2UgdmFsdWUgaXMgdGhlIG1heGltdW0gb2YgdGhlIGFyZ3VtZW50cy5cbiAgICAgICAgICpcbiAgICAgICAgICogYXJndW1lbnRzIHtudW1iZXJ8c3RyaW5nfEJpZ051bWJlcn1cbiAgICAgICAgICovXG4gICAgICAgIEJpZ051bWJlci5tYXggPSBmdW5jdGlvbiAoKSB7IHJldHVybiBtYXhPck1pbiggYXJndW1lbnRzLCBQLmx0ICk7IH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gYSBuZXcgQmlnTnVtYmVyIHdob3NlIHZhbHVlIGlzIHRoZSBtaW5pbXVtIG9mIHRoZSBhcmd1bWVudHMuXG4gICAgICAgICAqXG4gICAgICAgICAqIGFyZ3VtZW50cyB7bnVtYmVyfHN0cmluZ3xCaWdOdW1iZXJ9XG4gICAgICAgICAqL1xuICAgICAgICBCaWdOdW1iZXIubWluID0gZnVuY3Rpb24gKCkgeyByZXR1cm4gbWF4T3JNaW4oIGFyZ3VtZW50cywgUC5ndCApOyB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIGEgbmV3IEJpZ051bWJlciB3aXRoIGEgcmFuZG9tIHZhbHVlIGVxdWFsIHRvIG9yIGdyZWF0ZXIgdGhhbiAwIGFuZCBsZXNzIHRoYW4gMSxcbiAgICAgICAgICogYW5kIHdpdGggZHAsIG9yIERFQ0lNQUxfUExBQ0VTIGlmIGRwIGlzIG9taXR0ZWQsIGRlY2ltYWwgcGxhY2VzIChvciBsZXNzIGlmIHRyYWlsaW5nXG4gICAgICAgICAqIHplcm9zIGFyZSBwcm9kdWNlZCkuXG4gICAgICAgICAqXG4gICAgICAgICAqIFtkcF0ge251bWJlcn0gRGVjaW1hbCBwbGFjZXMuIEludGVnZXIsIDAgdG8gTUFYIGluY2x1c2l2ZS5cbiAgICAgICAgICpcbiAgICAgICAgICogJ3JhbmRvbSgpIGRlY2ltYWwgcGxhY2VzIG5vdCBhbiBpbnRlZ2VyOiB7ZHB9J1xuICAgICAgICAgKiAncmFuZG9tKCkgZGVjaW1hbCBwbGFjZXMgb3V0IG9mIHJhbmdlOiB7ZHB9J1xuICAgICAgICAgKiAncmFuZG9tKCkgY3J5cHRvIHVuYXZhaWxhYmxlOiB7Y3J5cHRvfSdcbiAgICAgICAgICovXG4gICAgICAgIEJpZ051bWJlci5yYW5kb20gPSAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHBvdzJfNTMgPSAweDIwMDAwMDAwMDAwMDAwO1xuXG4gICAgICAgICAgICAvLyBSZXR1cm4gYSA1MyBiaXQgaW50ZWdlciBuLCB3aGVyZSAwIDw9IG4gPCA5MDA3MTk5MjU0NzQwOTkyLlxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgTWF0aC5yYW5kb20oKSBwcm9kdWNlcyBtb3JlIHRoYW4gMzIgYml0cyBvZiByYW5kb21uZXNzLlxuICAgICAgICAgICAgLy8gSWYgaXQgZG9lcywgYXNzdW1lIGF0IGxlYXN0IDUzIGJpdHMgYXJlIHByb2R1Y2VkLCBvdGhlcndpc2UgYXNzdW1lIGF0IGxlYXN0IDMwIGJpdHMuXG4gICAgICAgICAgICAvLyAweDQwMDAwMDAwIGlzIDJeMzAsIDB4ODAwMDAwIGlzIDJeMjMsIDB4MWZmZmZmIGlzIDJeMjEgLSAxLlxuICAgICAgICAgICAgdmFyIHJhbmRvbTUzYml0SW50ID0gKE1hdGgucmFuZG9tKCkgKiBwb3cyXzUzKSAmIDB4MWZmZmZmXG4gICAgICAgICAgICAgID8gZnVuY3Rpb24gKCkgeyByZXR1cm4gbWF0aGZsb29yKCBNYXRoLnJhbmRvbSgpICogcG93Ml81MyApOyB9XG4gICAgICAgICAgICAgIDogZnVuY3Rpb24gKCkgeyByZXR1cm4gKChNYXRoLnJhbmRvbSgpICogMHg0MDAwMDAwMCB8IDApICogMHg4MDAwMDApICtcbiAgICAgICAgICAgICAgICAgIChNYXRoLnJhbmRvbSgpICogMHg4MDAwMDAgfCAwKTsgfTtcblxuICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChkcCkge1xuICAgICAgICAgICAgICAgIHZhciBhLCBiLCBlLCBrLCB2LFxuICAgICAgICAgICAgICAgICAgICBpID0gMCxcbiAgICAgICAgICAgICAgICAgICAgYyA9IFtdLFxuICAgICAgICAgICAgICAgICAgICByYW5kID0gbmV3IEJpZ051bWJlcihPTkUpO1xuXG4gICAgICAgICAgICAgICAgZHAgPSBkcCA9PSBudWxsIHx8ICFpc1ZhbGlkSW50KCBkcCwgMCwgTUFYLCAxNCApID8gREVDSU1BTF9QTEFDRVMgOiBkcCB8IDA7XG4gICAgICAgICAgICAgICAgayA9IG1hdGhjZWlsKCBkcCAvIExPR19CQVNFICk7XG5cbiAgICAgICAgICAgICAgICBpZiAoQ1JZUFRPKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gQnJvd3NlcnMgc3VwcG9ydGluZyBjcnlwdG8uZ2V0UmFuZG9tVmFsdWVzLlxuICAgICAgICAgICAgICAgICAgICBpZiAoIGNyeXB0byAmJiBjcnlwdG8uZ2V0UmFuZG9tVmFsdWVzICkge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBhID0gY3J5cHRvLmdldFJhbmRvbVZhbHVlcyggbmV3IFVpbnQzMkFycmF5KCBrICo9IDIgKSApO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBmb3IgKCA7IGkgPCBrOyApIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIDUzIGJpdHM6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gKChNYXRoLnBvdygyLCAzMikgLSAxKSAqIE1hdGgucG93KDIsIDIxKSkudG9TdHJpbmcoMilcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyAxMTExMSAxMTExMTExMSAxMTExMTExMSAxMTExMTExMSAxMTEwMDAwMCAwMDAwMDAwMCAwMDAwMDAwMFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vICgoTWF0aC5wb3coMiwgMzIpIC0gMSkgPj4+IDExKS50b1N0cmluZygyKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDExMTExIDExMTExMTExIDExMTExMTExXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gMHgyMDAwMCBpcyAyXjIxLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHYgPSBhW2ldICogMHgyMDAwMCArIChhW2kgKyAxXSA+Pj4gMTEpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gUmVqZWN0aW9uIHNhbXBsaW5nOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIDAgPD0gdiA8IDkwMDcxOTkyNTQ3NDA5OTJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBQcm9iYWJpbGl0eSB0aGF0IHYgPj0gOWUxNSwgaXNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyA3MTk5MjU0NzQwOTkyIC8gOTAwNzE5OTI1NDc0MDk5MiB+PSAwLjAwMDgsIGkuZS4gMSBpbiAxMjUxXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCB2ID49IDllMTUgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIgPSBjcnlwdG8uZ2V0UmFuZG9tVmFsdWVzKCBuZXcgVWludDMyQXJyYXkoMikgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYVtpXSA9IGJbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFbaSArIDFdID0gYlsxXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIDAgPD0gdiA8PSA4OTk5OTk5OTk5OTk5OTk5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIDAgPD0gKHYgJSAxZTE0KSA8PSA5OTk5OTk5OTk5OTk5OVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjLnB1c2goIHYgJSAxZTE0ICk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGkgKz0gMjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBpID0gayAvIDI7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gTm9kZS5qcyBzdXBwb3J0aW5nIGNyeXB0by5yYW5kb21CeXRlcy5cbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmICggY3J5cHRvICYmIGNyeXB0by5yYW5kb21CeXRlcyApIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYnVmZmVyXG4gICAgICAgICAgICAgICAgICAgICAgICBhID0gY3J5cHRvLnJhbmRvbUJ5dGVzKCBrICo9IDcgKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgZm9yICggOyBpIDwgazsgKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyAweDEwMDAwMDAwMDAwMDAgaXMgMl40OCwgMHgxMDAwMDAwMDAwMCBpcyAyXjQwXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gMHgxMDAwMDAwMDAgaXMgMl4zMiwgMHgxMDAwMDAwIGlzIDJeMjRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyAxMTExMSAxMTExMTExMSAxMTExMTExMSAxMTExMTExMSAxMTExMTExMSAxMTExMTExMSAxMTExMTExMVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIDAgPD0gdiA8IDkwMDcxOTkyNTQ3NDA5OTJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ID0gKCAoIGFbaV0gJiAzMSApICogMHgxMDAwMDAwMDAwMDAwICkgKyAoIGFbaSArIDFdICogMHgxMDAwMDAwMDAwMCApICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoIGFbaSArIDJdICogMHgxMDAwMDAwMDAgKSArICggYVtpICsgM10gKiAweDEwMDAwMDAgKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKCBhW2kgKyA0XSA8PCAxNiApICsgKCBhW2kgKyA1XSA8PCA4ICkgKyBhW2kgKyA2XTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICggdiA+PSA5ZTE1ICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjcnlwdG8ucmFuZG9tQnl0ZXMoNykuY29weSggYSwgaSApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gMCA8PSAodiAlIDFlMTQpIDw9IDk5OTk5OTk5OTk5OTk5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMucHVzaCggdiAlIDFlMTQgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaSArPSA3O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGkgPSBrIC8gNztcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChFUlJPUlMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJhaXNlKCAxNCwgJ2NyeXB0byB1bmF2YWlsYWJsZScsIGNyeXB0byApO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gVXNlIE1hdGgucmFuZG9tOiBDUllQVE8gaXMgZmFsc2Ugb3IgY3J5cHRvIGlzIHVuYXZhaWxhYmxlIGFuZCBFUlJPUlMgaXMgZmFsc2UuXG4gICAgICAgICAgICAgICAgaWYgKCFpKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgZm9yICggOyBpIDwgazsgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2ID0gcmFuZG9tNTNiaXRJbnQoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICggdiA8IDllMTUgKSBjW2krK10gPSB2ICUgMWUxNDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGsgPSBjWy0taV07XG4gICAgICAgICAgICAgICAgZHAgJT0gTE9HX0JBU0U7XG5cbiAgICAgICAgICAgICAgICAvLyBDb252ZXJ0IHRyYWlsaW5nIGRpZ2l0cyB0byB6ZXJvcyBhY2NvcmRpbmcgdG8gZHAuXG4gICAgICAgICAgICAgICAgaWYgKCBrICYmIGRwICkge1xuICAgICAgICAgICAgICAgICAgICB2ID0gUE9XU19URU5bTE9HX0JBU0UgLSBkcF07XG4gICAgICAgICAgICAgICAgICAgIGNbaV0gPSBtYXRoZmxvb3IoIGsgLyB2ICkgKiB2O1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIFJlbW92ZSB0cmFpbGluZyBlbGVtZW50cyB3aGljaCBhcmUgemVyby5cbiAgICAgICAgICAgICAgICBmb3IgKCA7IGNbaV0gPT09IDA7IGMucG9wKCksIGktLSApO1xuXG4gICAgICAgICAgICAgICAgLy8gWmVybz9cbiAgICAgICAgICAgICAgICBpZiAoIGkgPCAwICkge1xuICAgICAgICAgICAgICAgICAgICBjID0gWyBlID0gMCBdO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gUmVtb3ZlIGxlYWRpbmcgZWxlbWVudHMgd2hpY2ggYXJlIHplcm8gYW5kIGFkanVzdCBleHBvbmVudCBhY2NvcmRpbmdseS5cbiAgICAgICAgICAgICAgICAgICAgZm9yICggZSA9IC0xIDsgY1swXSA9PT0gMDsgYy5zaGlmdCgpLCBlIC09IExPR19CQVNFKTtcblxuICAgICAgICAgICAgICAgICAgICAvLyBDb3VudCB0aGUgZGlnaXRzIG9mIHRoZSBmaXJzdCBlbGVtZW50IG9mIGMgdG8gZGV0ZXJtaW5lIGxlYWRpbmcgemVyb3MsIGFuZC4uLlxuICAgICAgICAgICAgICAgICAgICBmb3IgKCBpID0gMSwgdiA9IGNbMF07IHYgPj0gMTA7IHYgLz0gMTAsIGkrKyk7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gYWRqdXN0IHRoZSBleHBvbmVudCBhY2NvcmRpbmdseS5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCBpIDwgTE9HX0JBU0UgKSBlIC09IExPR19CQVNFIC0gaTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByYW5kLmUgPSBlO1xuICAgICAgICAgICAgICAgIHJhbmQuYyA9IGM7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJhbmQ7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9KSgpO1xuXG5cbiAgICAgICAgLy8gUFJJVkFURSBGVU5DVElPTlNcblxuXG4gICAgICAgIC8vIENvbnZlcnQgYSBudW1lcmljIHN0cmluZyBvZiBiYXNlSW4gdG8gYSBudW1lcmljIHN0cmluZyBvZiBiYXNlT3V0LlxuICAgICAgICBmdW5jdGlvbiBjb252ZXJ0QmFzZSggc3RyLCBiYXNlT3V0LCBiYXNlSW4sIHNpZ24gKSB7XG4gICAgICAgICAgICB2YXIgZCwgZSwgaywgciwgeCwgeGMsIHksXG4gICAgICAgICAgICAgICAgaSA9IHN0ci5pbmRleE9mKCAnLicgKSxcbiAgICAgICAgICAgICAgICBkcCA9IERFQ0lNQUxfUExBQ0VTLFxuICAgICAgICAgICAgICAgIHJtID0gUk9VTkRJTkdfTU9ERTtcblxuICAgICAgICAgICAgaWYgKCBiYXNlSW4gPCAzNyApIHN0ciA9IHN0ci50b0xvd2VyQ2FzZSgpO1xuXG4gICAgICAgICAgICAvLyBOb24taW50ZWdlci5cbiAgICAgICAgICAgIGlmICggaSA+PSAwICkge1xuICAgICAgICAgICAgICAgIGsgPSBQT1dfUFJFQ0lTSU9OO1xuXG4gICAgICAgICAgICAgICAgLy8gVW5saW1pdGVkIHByZWNpc2lvbi5cbiAgICAgICAgICAgICAgICBQT1dfUFJFQ0lTSU9OID0gMDtcbiAgICAgICAgICAgICAgICBzdHIgPSBzdHIucmVwbGFjZSggJy4nLCAnJyApO1xuICAgICAgICAgICAgICAgIHkgPSBuZXcgQmlnTnVtYmVyKGJhc2VJbik7XG4gICAgICAgICAgICAgICAgeCA9IHkucG93KCBzdHIubGVuZ3RoIC0gaSApO1xuICAgICAgICAgICAgICAgIFBPV19QUkVDSVNJT04gPSBrO1xuXG4gICAgICAgICAgICAgICAgLy8gQ29udmVydCBzdHIgYXMgaWYgYW4gaW50ZWdlciwgdGhlbiByZXN0b3JlIHRoZSBmcmFjdGlvbiBwYXJ0IGJ5IGRpdmlkaW5nIHRoZVxuICAgICAgICAgICAgICAgIC8vIHJlc3VsdCBieSBpdHMgYmFzZSByYWlzZWQgdG8gYSBwb3dlci5cbiAgICAgICAgICAgICAgICB5LmMgPSB0b0Jhc2VPdXQoIHRvRml4ZWRQb2ludCggY29lZmZUb1N0cmluZyggeC5jICksIHguZSApLCAxMCwgYmFzZU91dCApO1xuICAgICAgICAgICAgICAgIHkuZSA9IHkuYy5sZW5ndGg7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIENvbnZlcnQgdGhlIG51bWJlciBhcyBpbnRlZ2VyLlxuICAgICAgICAgICAgeGMgPSB0b0Jhc2VPdXQoIHN0ciwgYmFzZUluLCBiYXNlT3V0ICk7XG4gICAgICAgICAgICBlID0gayA9IHhjLmxlbmd0aDtcblxuICAgICAgICAgICAgLy8gUmVtb3ZlIHRyYWlsaW5nIHplcm9zLlxuICAgICAgICAgICAgZm9yICggOyB4Y1stLWtdID09IDA7IHhjLnBvcCgpICk7XG4gICAgICAgICAgICBpZiAoICF4Y1swXSApIHJldHVybiAnMCc7XG5cbiAgICAgICAgICAgIGlmICggaSA8IDAgKSB7XG4gICAgICAgICAgICAgICAgLS1lO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB4LmMgPSB4YztcbiAgICAgICAgICAgICAgICB4LmUgPSBlO1xuXG4gICAgICAgICAgICAgICAgLy8gc2lnbiBpcyBuZWVkZWQgZm9yIGNvcnJlY3Qgcm91bmRpbmcuXG4gICAgICAgICAgICAgICAgeC5zID0gc2lnbjtcbiAgICAgICAgICAgICAgICB4ID0gZGl2KCB4LCB5LCBkcCwgcm0sIGJhc2VPdXQgKTtcbiAgICAgICAgICAgICAgICB4YyA9IHguYztcbiAgICAgICAgICAgICAgICByID0geC5yO1xuICAgICAgICAgICAgICAgIGUgPSB4LmU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGQgPSBlICsgZHAgKyAxO1xuXG4gICAgICAgICAgICAvLyBUaGUgcm91bmRpbmcgZGlnaXQsIGkuZS4gdGhlIGRpZ2l0IHRvIHRoZSByaWdodCBvZiB0aGUgZGlnaXQgdGhhdCBtYXkgYmUgcm91bmRlZCB1cC5cbiAgICAgICAgICAgIGkgPSB4Y1tkXTtcbiAgICAgICAgICAgIGsgPSBiYXNlT3V0IC8gMjtcbiAgICAgICAgICAgIHIgPSByIHx8IGQgPCAwIHx8IHhjW2QgKyAxXSAhPSBudWxsO1xuXG4gICAgICAgICAgICByID0gcm0gPCA0ID8gKCBpICE9IG51bGwgfHwgciApICYmICggcm0gPT0gMCB8fCBybSA9PSAoIHgucyA8IDAgPyAzIDogMiApIClcbiAgICAgICAgICAgICAgICAgICAgICAgOiBpID4gayB8fCBpID09IGsgJiYoIHJtID09IDQgfHwgciB8fCBybSA9PSA2ICYmIHhjW2QgLSAxXSAmIDEgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICBybSA9PSAoIHgucyA8IDAgPyA4IDogNyApICk7XG5cbiAgICAgICAgICAgIGlmICggZCA8IDEgfHwgIXhjWzBdICkge1xuXG4gICAgICAgICAgICAgICAgLy8gMV4tZHAgb3IgMC5cbiAgICAgICAgICAgICAgICBzdHIgPSByID8gdG9GaXhlZFBvaW50KCAnMScsIC1kcCApIDogJzAnO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB4Yy5sZW5ndGggPSBkO1xuXG4gICAgICAgICAgICAgICAgaWYgKHIpIHtcblxuICAgICAgICAgICAgICAgICAgICAvLyBSb3VuZGluZyB1cCBtYXkgbWVhbiB0aGUgcHJldmlvdXMgZGlnaXQgaGFzIHRvIGJlIHJvdW5kZWQgdXAgYW5kIHNvIG9uLlxuICAgICAgICAgICAgICAgICAgICBmb3IgKCAtLWJhc2VPdXQ7ICsreGNbLS1kXSA+IGJhc2VPdXQ7ICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgeGNbZF0gPSAwO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoICFkICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICsrZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB4Yy51bnNoaWZ0KDEpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gRGV0ZXJtaW5lIHRyYWlsaW5nIHplcm9zLlxuICAgICAgICAgICAgICAgIGZvciAoIGsgPSB4Yy5sZW5ndGg7ICF4Y1stLWtdOyApO1xuXG4gICAgICAgICAgICAgICAgLy8gRS5nLiBbNCwgMTEsIDE1XSBiZWNvbWVzIDRiZi5cbiAgICAgICAgICAgICAgICBmb3IgKCBpID0gMCwgc3RyID0gJyc7IGkgPD0gazsgc3RyICs9IEFMUEhBQkVULmNoYXJBdCggeGNbaSsrXSApICk7XG4gICAgICAgICAgICAgICAgc3RyID0gdG9GaXhlZFBvaW50KCBzdHIsIGUgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gVGhlIGNhbGxlciB3aWxsIGFkZCB0aGUgc2lnbi5cbiAgICAgICAgICAgIHJldHVybiBzdHI7XG4gICAgICAgIH1cblxuXG4gICAgICAgIC8vIFBlcmZvcm0gZGl2aXNpb24gaW4gdGhlIHNwZWNpZmllZCBiYXNlLiBDYWxsZWQgYnkgZGl2IGFuZCBjb252ZXJ0QmFzZS5cbiAgICAgICAgZGl2ID0gKGZ1bmN0aW9uICgpIHtcblxuICAgICAgICAgICAgLy8gQXNzdW1lIG5vbi16ZXJvIHggYW5kIGsuXG4gICAgICAgICAgICBmdW5jdGlvbiBtdWx0aXBseSggeCwgaywgYmFzZSApIHtcbiAgICAgICAgICAgICAgICB2YXIgbSwgdGVtcCwgeGxvLCB4aGksXG4gICAgICAgICAgICAgICAgICAgIGNhcnJ5ID0gMCxcbiAgICAgICAgICAgICAgICAgICAgaSA9IHgubGVuZ3RoLFxuICAgICAgICAgICAgICAgICAgICBrbG8gPSBrICUgU1FSVF9CQVNFLFxuICAgICAgICAgICAgICAgICAgICBraGkgPSBrIC8gU1FSVF9CQVNFIHwgMDtcblxuICAgICAgICAgICAgICAgIGZvciAoIHggPSB4LnNsaWNlKCk7IGktLTsgKSB7XG4gICAgICAgICAgICAgICAgICAgIHhsbyA9IHhbaV0gJSBTUVJUX0JBU0U7XG4gICAgICAgICAgICAgICAgICAgIHhoaSA9IHhbaV0gLyBTUVJUX0JBU0UgfCAwO1xuICAgICAgICAgICAgICAgICAgICBtID0ga2hpICogeGxvICsgeGhpICoga2xvO1xuICAgICAgICAgICAgICAgICAgICB0ZW1wID0ga2xvICogeGxvICsgKCAoIG0gJSBTUVJUX0JBU0UgKSAqIFNRUlRfQkFTRSApICsgY2Fycnk7XG4gICAgICAgICAgICAgICAgICAgIGNhcnJ5ID0gKCB0ZW1wIC8gYmFzZSB8IDAgKSArICggbSAvIFNRUlRfQkFTRSB8IDAgKSArIGtoaSAqIHhoaTtcbiAgICAgICAgICAgICAgICAgICAgeFtpXSA9IHRlbXAgJSBiYXNlO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmIChjYXJyeSkgeC51bnNoaWZ0KGNhcnJ5KTtcblxuICAgICAgICAgICAgICAgIHJldHVybiB4O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBmdW5jdGlvbiBjb21wYXJlKCBhLCBiLCBhTCwgYkwgKSB7XG4gICAgICAgICAgICAgICAgdmFyIGksIGNtcDtcblxuICAgICAgICAgICAgICAgIGlmICggYUwgIT0gYkwgKSB7XG4gICAgICAgICAgICAgICAgICAgIGNtcCA9IGFMID4gYkwgPyAxIDogLTE7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcblxuICAgICAgICAgICAgICAgICAgICBmb3IgKCBpID0gY21wID0gMDsgaSA8IGFMOyBpKysgKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICggYVtpXSAhPSBiW2ldICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNtcCA9IGFbaV0gPiBiW2ldID8gMSA6IC0xO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiBjbXA7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGZ1bmN0aW9uIHN1YnRyYWN0KCBhLCBiLCBhTCwgYmFzZSApIHtcbiAgICAgICAgICAgICAgICB2YXIgaSA9IDA7XG5cbiAgICAgICAgICAgICAgICAvLyBTdWJ0cmFjdCBiIGZyb20gYS5cbiAgICAgICAgICAgICAgICBmb3IgKCA7IGFMLS07ICkge1xuICAgICAgICAgICAgICAgICAgICBhW2FMXSAtPSBpO1xuICAgICAgICAgICAgICAgICAgICBpID0gYVthTF0gPCBiW2FMXSA/IDEgOiAwO1xuICAgICAgICAgICAgICAgICAgICBhW2FMXSA9IGkgKiBiYXNlICsgYVthTF0gLSBiW2FMXTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBSZW1vdmUgbGVhZGluZyB6ZXJvcy5cbiAgICAgICAgICAgICAgICBmb3IgKCA7ICFhWzBdICYmIGEubGVuZ3RoID4gMTsgYS5zaGlmdCgpICk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIHg6IGRpdmlkZW5kLCB5OiBkaXZpc29yLlxuICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uICggeCwgeSwgZHAsIHJtLCBiYXNlICkge1xuICAgICAgICAgICAgICAgIHZhciBjbXAsIGUsIGksIG1vcmUsIG4sIHByb2QsIHByb2RMLCBxLCBxYywgcmVtLCByZW1MLCByZW0wLCB4aSwgeEwsIHljMCxcbiAgICAgICAgICAgICAgICAgICAgeUwsIHl6LFxuICAgICAgICAgICAgICAgICAgICBzID0geC5zID09IHkucyA/IDEgOiAtMSxcbiAgICAgICAgICAgICAgICAgICAgeGMgPSB4LmMsXG4gICAgICAgICAgICAgICAgICAgIHljID0geS5jO1xuXG4gICAgICAgICAgICAgICAgLy8gRWl0aGVyIE5hTiwgSW5maW5pdHkgb3IgMD9cbiAgICAgICAgICAgICAgICBpZiAoICF4YyB8fCAheGNbMF0gfHwgIXljIHx8ICF5Y1swXSApIHtcblxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbmV3IEJpZ051bWJlcihcblxuICAgICAgICAgICAgICAgICAgICAgIC8vIFJldHVybiBOYU4gaWYgZWl0aGVyIE5hTiwgb3IgYm90aCBJbmZpbml0eSBvciAwLlxuICAgICAgICAgICAgICAgICAgICAgICF4LnMgfHwgIXkucyB8fCAoIHhjID8geWMgJiYgeGNbMF0gPT0geWNbMF0gOiAheWMgKSA/IE5hTiA6XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJldHVybiDCsTAgaWYgeCBpcyDCsTAgb3IgeSBpcyDCsUluZmluaXR5LCBvciByZXR1cm4gwrFJbmZpbml0eSBhcyB5IGlzIMKxMC5cbiAgICAgICAgICAgICAgICAgICAgICAgIHhjICYmIHhjWzBdID09IDAgfHwgIXljID8gcyAqIDAgOiBzIC8gMFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHEgPSBuZXcgQmlnTnVtYmVyKHMpO1xuICAgICAgICAgICAgICAgIHFjID0gcS5jID0gW107XG4gICAgICAgICAgICAgICAgZSA9IHguZSAtIHkuZTtcbiAgICAgICAgICAgICAgICBzID0gZHAgKyBlICsgMTtcblxuICAgICAgICAgICAgICAgIGlmICggIWJhc2UgKSB7XG4gICAgICAgICAgICAgICAgICAgIGJhc2UgPSBCQVNFO1xuICAgICAgICAgICAgICAgICAgICBlID0gYml0Rmxvb3IoIHguZSAvIExPR19CQVNFICkgLSBiaXRGbG9vciggeS5lIC8gTE9HX0JBU0UgKTtcbiAgICAgICAgICAgICAgICAgICAgcyA9IHMgLyBMT0dfQkFTRSB8IDA7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gUmVzdWx0IGV4cG9uZW50IG1heSBiZSBvbmUgbGVzcyB0aGVuIHRoZSBjdXJyZW50IHZhbHVlIG9mIGUuXG4gICAgICAgICAgICAgICAgLy8gVGhlIGNvZWZmaWNpZW50cyBvZiB0aGUgQmlnTnVtYmVycyBmcm9tIGNvbnZlcnRCYXNlIG1heSBoYXZlIHRyYWlsaW5nIHplcm9zLlxuICAgICAgICAgICAgICAgIGZvciAoIGkgPSAwOyB5Y1tpXSA9PSAoIHhjW2ldIHx8IDAgKTsgaSsrICk7XG4gICAgICAgICAgICAgICAgaWYgKCB5Y1tpXSA+ICggeGNbaV0gfHwgMCApICkgZS0tO1xuXG4gICAgICAgICAgICAgICAgaWYgKCBzIDwgMCApIHtcbiAgICAgICAgICAgICAgICAgICAgcWMucHVzaCgxKTtcbiAgICAgICAgICAgICAgICAgICAgbW9yZSA9IHRydWU7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgeEwgPSB4Yy5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgIHlMID0geWMubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICBpID0gMDtcbiAgICAgICAgICAgICAgICAgICAgcyArPSAyO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIE5vcm1hbGlzZSB4YyBhbmQgeWMgc28gaGlnaGVzdCBvcmRlciBkaWdpdCBvZiB5YyBpcyA+PSBiYXNlIC8gMi5cblxuICAgICAgICAgICAgICAgICAgICBuID0gbWF0aGZsb29yKCBiYXNlIC8gKCB5Y1swXSArIDEgKSApO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIE5vdCBuZWNlc3NhcnksIGJ1dCB0byBoYW5kbGUgb2RkIGJhc2VzIHdoZXJlIHljWzBdID09ICggYmFzZSAvIDIgKSAtIDEuXG4gICAgICAgICAgICAgICAgICAgIC8vIGlmICggbiA+IDEgfHwgbisrID09IDEgJiYgeWNbMF0gPCBiYXNlIC8gMiApIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCBuID4gMSApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHljID0gbXVsdGlwbHkoIHljLCBuLCBiYXNlICk7XG4gICAgICAgICAgICAgICAgICAgICAgICB4YyA9IG11bHRpcGx5KCB4YywgbiwgYmFzZSApO1xuICAgICAgICAgICAgICAgICAgICAgICAgeUwgPSB5Yy5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgICAgICB4TCA9IHhjLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHhpID0geUw7XG4gICAgICAgICAgICAgICAgICAgIHJlbSA9IHhjLnNsaWNlKCAwLCB5TCApO1xuICAgICAgICAgICAgICAgICAgICByZW1MID0gcmVtLmxlbmd0aDtcblxuICAgICAgICAgICAgICAgICAgICAvLyBBZGQgemVyb3MgdG8gbWFrZSByZW1haW5kZXIgYXMgbG9uZyBhcyBkaXZpc29yLlxuICAgICAgICAgICAgICAgICAgICBmb3IgKCA7IHJlbUwgPCB5TDsgcmVtW3JlbUwrK10gPSAwICk7XG4gICAgICAgICAgICAgICAgICAgIHl6ID0geWMuc2xpY2UoKTtcbiAgICAgICAgICAgICAgICAgICAgeXoudW5zaGlmdCgwKTtcbiAgICAgICAgICAgICAgICAgICAgeWMwID0geWNbMF07XG4gICAgICAgICAgICAgICAgICAgIGlmICggeWNbMV0gPj0gYmFzZSAvIDIgKSB5YzArKztcbiAgICAgICAgICAgICAgICAgICAgLy8gTm90IG5lY2Vzc2FyeSwgYnV0IHRvIHByZXZlbnQgdHJpYWwgZGlnaXQgbiA+IGJhc2UsIHdoZW4gdXNpbmcgYmFzZSAzLlxuICAgICAgICAgICAgICAgICAgICAvLyBlbHNlIGlmICggYmFzZSA9PSAzICYmIHljMCA9PSAxICkgeWMwID0gMSArIDFlLTE1O1xuXG4gICAgICAgICAgICAgICAgICAgIGRvIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG4gPSAwO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBDb21wYXJlIGRpdmlzb3IgYW5kIHJlbWFpbmRlci5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNtcCA9IGNvbXBhcmUoIHljLCByZW0sIHlMLCByZW1MICk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIGRpdmlzb3IgPCByZW1haW5kZXIuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIGNtcCA8IDAgKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBDYWxjdWxhdGUgdHJpYWwgZGlnaXQsIG4uXG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZW0wID0gcmVtWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICggeUwgIT0gcmVtTCApIHJlbTAgPSByZW0wICogYmFzZSArICggcmVtWzFdIHx8IDAgKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG4gaXMgaG93IG1hbnkgdGltZXMgdGhlIGRpdmlzb3IgZ29lcyBpbnRvIHRoZSBjdXJyZW50IHJlbWFpbmRlci5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuID0gbWF0aGZsb29yKCByZW0wIC8geWMwICk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyAgQWxnb3JpdGhtOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vICAxLiBwcm9kdWN0ID0gZGl2aXNvciAqIHRyaWFsIGRpZ2l0IChuKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vICAyLiBpZiBwcm9kdWN0ID4gcmVtYWluZGVyOiBwcm9kdWN0IC09IGRpdmlzb3IsIG4tLVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vICAzLiByZW1haW5kZXIgLT0gcHJvZHVjdFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vICA0LiBpZiBwcm9kdWN0IHdhcyA8IHJlbWFpbmRlciBhdCAyOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgIDUuIGNvbXBhcmUgbmV3IHJlbWFpbmRlciBhbmQgZGl2aXNvclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgIDYuIElmIHJlbWFpbmRlciA+IGRpdmlzb3I6IHJlbWFpbmRlciAtPSBkaXZpc29yLCBuKytcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICggbiA+IDEgKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gbiBtYXkgYmUgPiBiYXNlIG9ubHkgd2hlbiBiYXNlIGlzIDMuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChuID49IGJhc2UpIG4gPSBiYXNlIC0gMTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBwcm9kdWN0ID0gZGl2aXNvciAqIHRyaWFsIGRpZ2l0LlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kID0gbXVsdGlwbHkoIHljLCBuLCBiYXNlICk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2RMID0gcHJvZC5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbUwgPSByZW0ubGVuZ3RoO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIENvbXBhcmUgcHJvZHVjdCBhbmQgcmVtYWluZGVyLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJZiBwcm9kdWN0ID4gcmVtYWluZGVyLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBUcmlhbCBkaWdpdCBuIHRvbyBoaWdoLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBuIGlzIDEgdG9vIGhpZ2ggYWJvdXQgNSUgb2YgdGhlIHRpbWUsIGFuZCBpcyBub3Qga25vd24gdG8gaGF2ZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBldmVyIGJlZW4gbW9yZSB0aGFuIDEgdG9vIGhpZ2guXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWxlICggY29tcGFyZSggcHJvZCwgcmVtLCBwcm9kTCwgcmVtTCApID09IDEgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuLS07XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFN1YnRyYWN0IGRpdmlzb3IgZnJvbSBwcm9kdWN0LlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VidHJhY3QoIHByb2QsIHlMIDwgcHJvZEwgPyB5eiA6IHljLCBwcm9kTCwgYmFzZSApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZEwgPSBwcm9kLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNtcCA9IDE7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG4gaXMgMCBvciAxLCBjbXAgaXMgLTEuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIG4gaXMgMCwgdGhlcmUgaXMgbm8gbmVlZCB0byBjb21wYXJlIHljIGFuZCByZW0gYWdhaW4gYmVsb3csXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHNvIGNoYW5nZSBjbXAgdG8gMSB0byBhdm9pZCBpdC5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSWYgbiBpcyAxLCBsZWF2ZSBjbXAgYXMgLTEsIHNvIHljIGFuZCByZW0gYXJlIGNvbXBhcmVkIGFnYWluLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIG4gPT0gMCApIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZGl2aXNvciA8IHJlbWFpbmRlciwgc28gbiBtdXN0IGJlIGF0IGxlYXN0IDEuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbXAgPSBuID0gMTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHByb2R1Y3QgPSBkaXZpc29yXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2QgPSB5Yy5zbGljZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kTCA9IHByb2QubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICggcHJvZEwgPCByZW1MICkgcHJvZC51bnNoaWZ0KDApO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU3VidHJhY3QgcHJvZHVjdCBmcm9tIHJlbWFpbmRlci5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJ0cmFjdCggcmVtLCBwcm9kLCByZW1MLCBiYXNlICk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVtTCA9IHJlbS5sZW5ndGg7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSWYgcHJvZHVjdCB3YXMgPCByZW1haW5kZXIuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCBjbXAgPT0gLTEgKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ29tcGFyZSBkaXZpc29yIGFuZCBuZXcgcmVtYWluZGVyLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJZiBkaXZpc29yIDwgbmV3IHJlbWFpbmRlciwgc3VidHJhY3QgZGl2aXNvciBmcm9tIHJlbWFpbmRlci5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVHJpYWwgZGlnaXQgbiB0b28gbG93LlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBuIGlzIDEgdG9vIGxvdyBhYm91dCA1JSBvZiB0aGUgdGltZSwgYW5kIHZlcnkgcmFyZWx5IDIgdG9vIGxvdy5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpbGUgKCBjb21wYXJlKCB5YywgcmVtLCB5TCwgcmVtTCApIDwgMSApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4rKztcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU3VidHJhY3QgZGl2aXNvciBmcm9tIHJlbWFpbmRlci5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnRyYWN0KCByZW0sIHlMIDwgcmVtTCA/IHl6IDogeWMsIHJlbUwsIGJhc2UgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbUwgPSByZW0ubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmICggY21wID09PSAwICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4rKztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZW0gPSBbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICB9IC8vIGVsc2UgY21wID09PSAxIGFuZCBuIHdpbGwgYmUgMFxuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBBZGQgdGhlIG5leHQgZGlnaXQsIG4sIHRvIHRoZSByZXN1bHQgYXJyYXkuXG4gICAgICAgICAgICAgICAgICAgICAgICBxY1tpKytdID0gbjtcblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVXBkYXRlIHRoZSByZW1haW5kZXIuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIHJlbVswXSApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZW1bcmVtTCsrXSA9IHhjW3hpXSB8fCAwO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZW0gPSBbIHhjW3hpXSBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbUwgPSAxO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9IHdoaWxlICggKCB4aSsrIDwgeEwgfHwgcmVtWzBdICE9IG51bGwgKSAmJiBzLS0gKTtcblxuICAgICAgICAgICAgICAgICAgICBtb3JlID0gcmVtWzBdICE9IG51bGw7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gTGVhZGluZyB6ZXJvP1xuICAgICAgICAgICAgICAgICAgICBpZiAoICFxY1swXSApIHFjLnNoaWZ0KCk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKCBiYXNlID09IEJBU0UgKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gVG8gY2FsY3VsYXRlIHEuZSwgZmlyc3QgZ2V0IHRoZSBudW1iZXIgb2YgZGlnaXRzIG9mIHFjWzBdLlxuICAgICAgICAgICAgICAgICAgICBmb3IgKCBpID0gMSwgcyA9IHFjWzBdOyBzID49IDEwOyBzIC89IDEwLCBpKysgKTtcbiAgICAgICAgICAgICAgICAgICAgcm91bmQoIHEsIGRwICsgKCBxLmUgPSBpICsgZSAqIExPR19CQVNFIC0gMSApICsgMSwgcm0sIG1vcmUgKTtcblxuICAgICAgICAgICAgICAgIC8vIENhbGxlciBpcyBjb252ZXJ0QmFzZS5cbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBxLmUgPSBlO1xuICAgICAgICAgICAgICAgICAgICBxLnIgPSArbW9yZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gcTtcbiAgICAgICAgICAgIH07XG4gICAgICAgIH0pKCk7XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gYSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSB2YWx1ZSBvZiBCaWdOdW1iZXIgbiBpbiBmaXhlZC1wb2ludCBvciBleHBvbmVudGlhbFxuICAgICAgICAgKiBub3RhdGlvbiByb3VuZGVkIHRvIHRoZSBzcGVjaWZpZWQgZGVjaW1hbCBwbGFjZXMgb3Igc2lnbmlmaWNhbnQgZGlnaXRzLlxuICAgICAgICAgKlxuICAgICAgICAgKiBuIGlzIGEgQmlnTnVtYmVyLlxuICAgICAgICAgKiBpIGlzIHRoZSBpbmRleCBvZiB0aGUgbGFzdCBkaWdpdCByZXF1aXJlZCAoaS5lLiB0aGUgZGlnaXQgdGhhdCBtYXkgYmUgcm91bmRlZCB1cCkuXG4gICAgICAgICAqIHJtIGlzIHRoZSByb3VuZGluZyBtb2RlLlxuICAgICAgICAgKiBjYWxsZXIgaXMgY2FsbGVyIGlkOiB0b0V4cG9uZW50aWFsIDE5LCB0b0ZpeGVkIDIwLCB0b0Zvcm1hdCAyMSwgdG9QcmVjaXNpb24gMjQuXG4gICAgICAgICAqL1xuICAgICAgICBmdW5jdGlvbiBmb3JtYXQoIG4sIGksIHJtLCBjYWxsZXIgKSB7XG4gICAgICAgICAgICB2YXIgYzAsIGUsIG5lLCBsZW4sIHN0cjtcblxuICAgICAgICAgICAgcm0gPSBybSAhPSBudWxsICYmIGlzVmFsaWRJbnQoIHJtLCAwLCA4LCBjYWxsZXIsIHJvdW5kaW5nTW9kZSApXG4gICAgICAgICAgICAgID8gcm0gfCAwIDogUk9VTkRJTkdfTU9ERTtcblxuICAgICAgICAgICAgaWYgKCAhbi5jICkgcmV0dXJuIG4udG9TdHJpbmcoKTtcbiAgICAgICAgICAgIGMwID0gbi5jWzBdO1xuICAgICAgICAgICAgbmUgPSBuLmU7XG5cbiAgICAgICAgICAgIGlmICggaSA9PSBudWxsICkge1xuICAgICAgICAgICAgICAgIHN0ciA9IGNvZWZmVG9TdHJpbmcoIG4uYyApO1xuICAgICAgICAgICAgICAgIHN0ciA9IGNhbGxlciA9PSAxOSB8fCBjYWxsZXIgPT0gMjQgJiYgbmUgPD0gVE9fRVhQX05FR1xuICAgICAgICAgICAgICAgICAgPyB0b0V4cG9uZW50aWFsKCBzdHIsIG5lIClcbiAgICAgICAgICAgICAgICAgIDogdG9GaXhlZFBvaW50KCBzdHIsIG5lICk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIG4gPSByb3VuZCggbmV3IEJpZ051bWJlcihuKSwgaSwgcm0gKTtcblxuICAgICAgICAgICAgICAgIC8vIG4uZSBtYXkgaGF2ZSBjaGFuZ2VkIGlmIHRoZSB2YWx1ZSB3YXMgcm91bmRlZCB1cC5cbiAgICAgICAgICAgICAgICBlID0gbi5lO1xuXG4gICAgICAgICAgICAgICAgc3RyID0gY29lZmZUb1N0cmluZyggbi5jICk7XG4gICAgICAgICAgICAgICAgbGVuID0gc3RyLmxlbmd0aDtcblxuICAgICAgICAgICAgICAgIC8vIHRvUHJlY2lzaW9uIHJldHVybnMgZXhwb25lbnRpYWwgbm90YXRpb24gaWYgdGhlIG51bWJlciBvZiBzaWduaWZpY2FudCBkaWdpdHNcbiAgICAgICAgICAgICAgICAvLyBzcGVjaWZpZWQgaXMgbGVzcyB0aGFuIHRoZSBudW1iZXIgb2YgZGlnaXRzIG5lY2Vzc2FyeSB0byByZXByZXNlbnQgdGhlIGludGVnZXJcbiAgICAgICAgICAgICAgICAvLyBwYXJ0IG9mIHRoZSB2YWx1ZSBpbiBmaXhlZC1wb2ludCBub3RhdGlvbi5cblxuICAgICAgICAgICAgICAgIC8vIEV4cG9uZW50aWFsIG5vdGF0aW9uLlxuICAgICAgICAgICAgICAgIGlmICggY2FsbGVyID09IDE5IHx8IGNhbGxlciA9PSAyNCAmJiAoIGkgPD0gZSB8fCBlIDw9IFRPX0VYUF9ORUcgKSApIHtcblxuICAgICAgICAgICAgICAgICAgICAvLyBBcHBlbmQgemVyb3M/XG4gICAgICAgICAgICAgICAgICAgIGZvciAoIDsgbGVuIDwgaTsgc3RyICs9ICcwJywgbGVuKysgKTtcbiAgICAgICAgICAgICAgICAgICAgc3RyID0gdG9FeHBvbmVudGlhbCggc3RyLCBlICk7XG5cbiAgICAgICAgICAgICAgICAvLyBGaXhlZC1wb2ludCBub3RhdGlvbi5cbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBpIC09IG5lO1xuICAgICAgICAgICAgICAgICAgICBzdHIgPSB0b0ZpeGVkUG9pbnQoIHN0ciwgZSApO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIEFwcGVuZCB6ZXJvcz9cbiAgICAgICAgICAgICAgICAgICAgaWYgKCBlICsgMSA+IGxlbiApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICggLS1pID4gMCApIGZvciAoIHN0ciArPSAnLic7IGktLTsgc3RyICs9ICcwJyApO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgaSArPSBlIC0gbGVuO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCBpID4gMCApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIGUgKyAxID09IGxlbiApIHN0ciArPSAnLic7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yICggOyBpLS07IHN0ciArPSAnMCcgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIG4ucyA8IDAgJiYgYzAgPyAnLScgKyBzdHIgOiBzdHI7XG4gICAgICAgIH1cblxuXG4gICAgICAgIC8vIEhhbmRsZSBCaWdOdW1iZXIubWF4IGFuZCBCaWdOdW1iZXIubWluLlxuICAgICAgICBmdW5jdGlvbiBtYXhPck1pbiggYXJncywgbWV0aG9kICkge1xuICAgICAgICAgICAgdmFyIG0sIG4sXG4gICAgICAgICAgICAgICAgaSA9IDA7XG5cbiAgICAgICAgICAgIGlmICggaXNBcnJheSggYXJnc1swXSApICkgYXJncyA9IGFyZ3NbMF07XG4gICAgICAgICAgICBtID0gbmV3IEJpZ051bWJlciggYXJnc1swXSApO1xuXG4gICAgICAgICAgICBmb3IgKCA7ICsraSA8IGFyZ3MubGVuZ3RoOyApIHtcbiAgICAgICAgICAgICAgICBuID0gbmV3IEJpZ051bWJlciggYXJnc1tpXSApO1xuXG4gICAgICAgICAgICAgICAgLy8gSWYgYW55IG51bWJlciBpcyBOYU4sIHJldHVybiBOYU4uXG4gICAgICAgICAgICAgICAgaWYgKCAhbi5zICkge1xuICAgICAgICAgICAgICAgICAgICBtID0gbjtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmICggbWV0aG9kLmNhbGwoIG0sIG4gKSApIHtcbiAgICAgICAgICAgICAgICAgICAgbSA9IG47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gbTtcbiAgICAgICAgfVxuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIHRydWUgaWYgbiBpcyBhbiBpbnRlZ2VyIGluIHJhbmdlLCBvdGhlcndpc2UgdGhyb3cuXG4gICAgICAgICAqIFVzZSBmb3IgYXJndW1lbnQgdmFsaWRhdGlvbiB3aGVuIEVSUk9SUyBpcyB0cnVlLlxuICAgICAgICAgKi9cbiAgICAgICAgZnVuY3Rpb24gaW50VmFsaWRhdG9yV2l0aEVycm9ycyggbiwgbWluLCBtYXgsIGNhbGxlciwgbmFtZSApIHtcbiAgICAgICAgICAgIGlmICggbiA8IG1pbiB8fCBuID4gbWF4IHx8IG4gIT0gdHJ1bmNhdGUobikgKSB7XG4gICAgICAgICAgICAgICAgcmFpc2UoIGNhbGxlciwgKCBuYW1lIHx8ICdkZWNpbWFsIHBsYWNlcycgKSArXG4gICAgICAgICAgICAgICAgICAoIG4gPCBtaW4gfHwgbiA+IG1heCA/ICcgb3V0IG9mIHJhbmdlJyA6ICcgbm90IGFuIGludGVnZXInICksIG4gKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFN0cmlwIHRyYWlsaW5nIHplcm9zLCBjYWxjdWxhdGUgYmFzZSAxMCBleHBvbmVudCBhbmQgY2hlY2sgYWdhaW5zdCBNSU5fRVhQIGFuZCBNQVhfRVhQLlxuICAgICAgICAgKiBDYWxsZWQgYnkgbWludXMsIHBsdXMgYW5kIHRpbWVzLlxuICAgICAgICAgKi9cbiAgICAgICAgZnVuY3Rpb24gbm9ybWFsaXNlKCBuLCBjLCBlICkge1xuICAgICAgICAgICAgdmFyIGkgPSAxLFxuICAgICAgICAgICAgICAgIGogPSBjLmxlbmd0aDtcblxuICAgICAgICAgICAgIC8vIFJlbW92ZSB0cmFpbGluZyB6ZXJvcy5cbiAgICAgICAgICAgIGZvciAoIDsgIWNbLS1qXTsgYy5wb3AoKSApO1xuXG4gICAgICAgICAgICAvLyBDYWxjdWxhdGUgdGhlIGJhc2UgMTAgZXhwb25lbnQuIEZpcnN0IGdldCB0aGUgbnVtYmVyIG9mIGRpZ2l0cyBvZiBjWzBdLlxuICAgICAgICAgICAgZm9yICggaiA9IGNbMF07IGogPj0gMTA7IGogLz0gMTAsIGkrKyApO1xuXG4gICAgICAgICAgICAvLyBPdmVyZmxvdz9cbiAgICAgICAgICAgIGlmICggKCBlID0gaSArIGUgKiBMT0dfQkFTRSAtIDEgKSA+IE1BWF9FWFAgKSB7XG5cbiAgICAgICAgICAgICAgICAvLyBJbmZpbml0eS5cbiAgICAgICAgICAgICAgICBuLmMgPSBuLmUgPSBudWxsO1xuXG4gICAgICAgICAgICAvLyBVbmRlcmZsb3c/XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCBlIDwgTUlOX0VYUCApIHtcblxuICAgICAgICAgICAgICAgIC8vIFplcm8uXG4gICAgICAgICAgICAgICAgbi5jID0gWyBuLmUgPSAwIF07XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIG4uZSA9IGU7XG4gICAgICAgICAgICAgICAgbi5jID0gYztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIG47XG4gICAgICAgIH1cblxuXG4gICAgICAgIC8vIEhhbmRsZSB2YWx1ZXMgdGhhdCBmYWlsIHRoZSB2YWxpZGl0eSB0ZXN0IGluIEJpZ051bWJlci5cbiAgICAgICAgcGFyc2VOdW1lcmljID0gKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBiYXNlUHJlZml4ID0gL14oLT8pMChbeGJvXSkvaSxcbiAgICAgICAgICAgICAgICBkb3RBZnRlciA9IC9eKFteLl0rKVxcLiQvLFxuICAgICAgICAgICAgICAgIGRvdEJlZm9yZSA9IC9eXFwuKFteLl0rKSQvLFxuICAgICAgICAgICAgICAgIGlzSW5maW5pdHlPck5hTiA9IC9eLT8oSW5maW5pdHl8TmFOKSQvLFxuICAgICAgICAgICAgICAgIHdoaXRlc3BhY2VPclBsdXMgPSAvXlxccypcXCt8Xlxccyt8XFxzKyQvZztcblxuICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uICggeCwgc3RyLCBudW0sIGIgKSB7XG4gICAgICAgICAgICAgICAgdmFyIGJhc2UsXG4gICAgICAgICAgICAgICAgICAgIHMgPSBudW0gPyBzdHIgOiBzdHIucmVwbGFjZSggd2hpdGVzcGFjZU9yUGx1cywgJycgKTtcblxuICAgICAgICAgICAgICAgIC8vIE5vIGV4Y2VwdGlvbiBvbiDCsUluZmluaXR5IG9yIE5hTi5cbiAgICAgICAgICAgICAgICBpZiAoIGlzSW5maW5pdHlPck5hTi50ZXN0KHMpICkge1xuICAgICAgICAgICAgICAgICAgICB4LnMgPSBpc05hTihzKSA/IG51bGwgOiBzIDwgMCA/IC0xIDogMTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBpZiAoICFudW0gKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGJhc2VQcmVmaXggPSAvXigtPykwKFt4Ym9dKSg/PVxcd1tcXHcuXSokKS9pXG4gICAgICAgICAgICAgICAgICAgICAgICBzID0gcy5yZXBsYWNlKCBiYXNlUHJlZml4LCBmdW5jdGlvbiAoIG0sIHAxLCBwMiApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXNlID0gKCBwMiA9IHAyLnRvTG93ZXJDYXNlKCkgKSA9PSAneCcgPyAxNiA6IHAyID09ICdiJyA/IDIgOiA4O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAhYiB8fCBiID09IGJhc2UgPyBwMSA6IG07XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXNlID0gYjtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEUuZy4gJzEuJyB0byAnMScsICcuMScgdG8gJzAuMSdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzID0gcy5yZXBsYWNlKCBkb3RBZnRlciwgJyQxJyApLnJlcGxhY2UoIGRvdEJlZm9yZSwgJzAuJDEnICk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICggc3RyICE9IHMgKSByZXR1cm4gbmV3IEJpZ051bWJlciggcywgYmFzZSApO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gJ25ldyBCaWdOdW1iZXIoKSBub3QgYSBudW1iZXI6IHtufSdcbiAgICAgICAgICAgICAgICAgICAgLy8gJ25ldyBCaWdOdW1iZXIoKSBub3QgYSBiYXNlIHtifSBudW1iZXI6IHtufSdcbiAgICAgICAgICAgICAgICAgICAgaWYgKEVSUk9SUykgcmFpc2UoIGlkLCAnbm90IGEnICsgKCBiID8gJyBiYXNlICcgKyBiIDogJycgKSArICcgbnVtYmVyJywgc3RyICk7XG4gICAgICAgICAgICAgICAgICAgIHgucyA9IG51bGw7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgeC5jID0geC5lID0gbnVsbDtcbiAgICAgICAgICAgICAgICBpZCA9IDA7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pKCk7XG5cblxuICAgICAgICAvLyBUaHJvdyBhIEJpZ051bWJlciBFcnJvci5cbiAgICAgICAgZnVuY3Rpb24gcmFpc2UoIGNhbGxlciwgbXNnLCB2YWwgKSB7XG4gICAgICAgICAgICB2YXIgZXJyb3IgPSBuZXcgRXJyb3IoIFtcbiAgICAgICAgICAgICAgICAnbmV3IEJpZ051bWJlcicsICAgICAvLyAwXG4gICAgICAgICAgICAgICAgJ2NtcCcsICAgICAgICAgICAgICAgLy8gMVxuICAgICAgICAgICAgICAgICdjb25maWcnLCAgICAgICAgICAgIC8vIDJcbiAgICAgICAgICAgICAgICAnZGl2JywgICAgICAgICAgICAgICAvLyAzXG4gICAgICAgICAgICAgICAgJ2RpdlRvSW50JywgICAgICAgICAgLy8gNFxuICAgICAgICAgICAgICAgICdlcScsICAgICAgICAgICAgICAgIC8vIDVcbiAgICAgICAgICAgICAgICAnZ3QnLCAgICAgICAgICAgICAgICAvLyA2XG4gICAgICAgICAgICAgICAgJ2d0ZScsICAgICAgICAgICAgICAgLy8gN1xuICAgICAgICAgICAgICAgICdsdCcsICAgICAgICAgICAgICAgIC8vIDhcbiAgICAgICAgICAgICAgICAnbHRlJywgICAgICAgICAgICAgICAvLyA5XG4gICAgICAgICAgICAgICAgJ21pbnVzJywgICAgICAgICAgICAgLy8gMTBcbiAgICAgICAgICAgICAgICAnbW9kJywgICAgICAgICAgICAgICAvLyAxMVxuICAgICAgICAgICAgICAgICdwbHVzJywgICAgICAgICAgICAgIC8vIDEyXG4gICAgICAgICAgICAgICAgJ3ByZWNpc2lvbicsICAgICAgICAgLy8gMTNcbiAgICAgICAgICAgICAgICAncmFuZG9tJywgICAgICAgICAgICAvLyAxNFxuICAgICAgICAgICAgICAgICdyb3VuZCcsICAgICAgICAgICAgIC8vIDE1XG4gICAgICAgICAgICAgICAgJ3NoaWZ0JywgICAgICAgICAgICAgLy8gMTZcbiAgICAgICAgICAgICAgICAndGltZXMnLCAgICAgICAgICAgICAvLyAxN1xuICAgICAgICAgICAgICAgICd0b0RpZ2l0cycsICAgICAgICAgIC8vIDE4XG4gICAgICAgICAgICAgICAgJ3RvRXhwb25lbnRpYWwnLCAgICAgLy8gMTlcbiAgICAgICAgICAgICAgICAndG9GaXhlZCcsICAgICAgICAgICAvLyAyMFxuICAgICAgICAgICAgICAgICd0b0Zvcm1hdCcsICAgICAgICAgIC8vIDIxXG4gICAgICAgICAgICAgICAgJ3RvRnJhY3Rpb24nLCAgICAgICAgLy8gMjJcbiAgICAgICAgICAgICAgICAncG93JywgICAgICAgICAgICAgICAvLyAyM1xuICAgICAgICAgICAgICAgICd0b1ByZWNpc2lvbicsICAgICAgIC8vIDI0XG4gICAgICAgICAgICAgICAgJ3RvU3RyaW5nJywgICAgICAgICAgLy8gMjVcbiAgICAgICAgICAgICAgICAnQmlnTnVtYmVyJyAgICAgICAgICAvLyAyNlxuICAgICAgICAgICAgXVtjYWxsZXJdICsgJygpICcgKyBtc2cgKyAnOiAnICsgdmFsICk7XG5cbiAgICAgICAgICAgIGVycm9yLm5hbWUgPSAnQmlnTnVtYmVyIEVycm9yJztcbiAgICAgICAgICAgIGlkID0gMDtcbiAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICB9XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSb3VuZCB4IHRvIHNkIHNpZ25pZmljYW50IGRpZ2l0cyB1c2luZyByb3VuZGluZyBtb2RlIHJtLiBDaGVjayBmb3Igb3Zlci91bmRlci1mbG93LlxuICAgICAgICAgKiBJZiByIGlzIHRydXRoeSwgaXQgaXMga25vd24gdGhhdCB0aGVyZSBhcmUgbW9yZSBkaWdpdHMgYWZ0ZXIgdGhlIHJvdW5kaW5nIGRpZ2l0LlxuICAgICAgICAgKi9cbiAgICAgICAgZnVuY3Rpb24gcm91bmQoIHgsIHNkLCBybSwgciApIHtcbiAgICAgICAgICAgIHZhciBkLCBpLCBqLCBrLCBuLCBuaSwgcmQsXG4gICAgICAgICAgICAgICAgeGMgPSB4LmMsXG4gICAgICAgICAgICAgICAgcG93czEwID0gUE9XU19URU47XG5cbiAgICAgICAgICAgIC8vIGlmIHggaXMgbm90IEluZmluaXR5IG9yIE5hTi4uLlxuICAgICAgICAgICAgaWYgKHhjKSB7XG5cbiAgICAgICAgICAgICAgICAvLyByZCBpcyB0aGUgcm91bmRpbmcgZGlnaXQsIGkuZS4gdGhlIGRpZ2l0IGFmdGVyIHRoZSBkaWdpdCB0aGF0IG1heSBiZSByb3VuZGVkIHVwLlxuICAgICAgICAgICAgICAgIC8vIG4gaXMgYSBiYXNlIDFlMTQgbnVtYmVyLCB0aGUgdmFsdWUgb2YgdGhlIGVsZW1lbnQgb2YgYXJyYXkgeC5jIGNvbnRhaW5pbmcgcmQuXG4gICAgICAgICAgICAgICAgLy8gbmkgaXMgdGhlIGluZGV4IG9mIG4gd2l0aGluIHguYy5cbiAgICAgICAgICAgICAgICAvLyBkIGlzIHRoZSBudW1iZXIgb2YgZGlnaXRzIG9mIG4uXG4gICAgICAgICAgICAgICAgLy8gaSBpcyB0aGUgaW5kZXggb2YgcmQgd2l0aGluIG4gaW5jbHVkaW5nIGxlYWRpbmcgemVyb3MuXG4gICAgICAgICAgICAgICAgLy8gaiBpcyB0aGUgYWN0dWFsIGluZGV4IG9mIHJkIHdpdGhpbiBuIChpZiA8IDAsIHJkIGlzIGEgbGVhZGluZyB6ZXJvKS5cbiAgICAgICAgICAgICAgICBvdXQ6IHtcblxuICAgICAgICAgICAgICAgICAgICAvLyBHZXQgdGhlIG51bWJlciBvZiBkaWdpdHMgb2YgdGhlIGZpcnN0IGVsZW1lbnQgb2YgeGMuXG4gICAgICAgICAgICAgICAgICAgIGZvciAoIGQgPSAxLCBrID0geGNbMF07IGsgPj0gMTA7IGsgLz0gMTAsIGQrKyApO1xuICAgICAgICAgICAgICAgICAgICBpID0gc2QgLSBkO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIElmIHRoZSByb3VuZGluZyBkaWdpdCBpcyBpbiB0aGUgZmlyc3QgZWxlbWVudCBvZiB4Yy4uLlxuICAgICAgICAgICAgICAgICAgICBpZiAoIGkgPCAwICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaSArPSBMT0dfQkFTRTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGogPSBzZDtcbiAgICAgICAgICAgICAgICAgICAgICAgIG4gPSB4Y1sgbmkgPSAwIF07XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEdldCB0aGUgcm91bmRpbmcgZGlnaXQgYXQgaW5kZXggaiBvZiBuLlxuICAgICAgICAgICAgICAgICAgICAgICAgcmQgPSBuIC8gcG93czEwWyBkIC0gaiAtIDEgXSAlIDEwIHwgMDtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG5pID0gbWF0aGNlaWwoICggaSArIDEgKSAvIExPR19CQVNFICk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICggbmkgPj0geGMubGVuZ3RoICkge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHIpIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBOZWVkZWQgYnkgc3FydC5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yICggOyB4Yy5sZW5ndGggPD0gbmk7IHhjLnB1c2goMCkgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbiA9IHJkID0gMDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZCA9IDE7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGkgJT0gTE9HX0JBU0U7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGogPSBpIC0gTE9HX0JBU0UgKyAxO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrIG91dDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4gPSBrID0geGNbbmldO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gR2V0IHRoZSBudW1iZXIgb2YgZGlnaXRzIG9mIG4uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yICggZCA9IDE7IGsgPj0gMTA7IGsgLz0gMTAsIGQrKyApO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gR2V0IHRoZSBpbmRleCBvZiByZCB3aXRoaW4gbi5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpICU9IExPR19CQVNFO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gR2V0IHRoZSBpbmRleCBvZiByZCB3aXRoaW4gbiwgYWRqdXN0ZWQgZm9yIGxlYWRpbmcgemVyb3MuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gVGhlIG51bWJlciBvZiBsZWFkaW5nIHplcm9zIG9mIG4gaXMgZ2l2ZW4gYnkgTE9HX0JBU0UgLSBkLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGogPSBpIC0gTE9HX0JBU0UgKyBkO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gR2V0IHRoZSByb3VuZGluZyBkaWdpdCBhdCBpbmRleCBqIG9mIG4uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmQgPSBqIDwgMCA/IDAgOiBuIC8gcG93czEwWyBkIC0gaiAtIDEgXSAlIDEwIHwgMDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHIgPSByIHx8IHNkIDwgMCB8fFxuXG4gICAgICAgICAgICAgICAgICAgIC8vIEFyZSB0aGVyZSBhbnkgbm9uLXplcm8gZGlnaXRzIGFmdGVyIHRoZSByb3VuZGluZyBkaWdpdD9cbiAgICAgICAgICAgICAgICAgICAgLy8gVGhlIGV4cHJlc3Npb24gIG4gJSBwb3dzMTBbIGQgLSBqIC0gMSBdICByZXR1cm5zIGFsbCBkaWdpdHMgb2YgbiB0byB0aGUgcmlnaHRcbiAgICAgICAgICAgICAgICAgICAgLy8gb2YgdGhlIGRpZ2l0IGF0IGosIGUuZy4gaWYgbiBpcyA5MDg3MTQgYW5kIGogaXMgMiwgdGhlIGV4cHJlc3Npb24gZ2l2ZXMgNzE0LlxuICAgICAgICAgICAgICAgICAgICAgIHhjW25pICsgMV0gIT0gbnVsbCB8fCAoIGogPCAwID8gbiA6IG4gJSBwb3dzMTBbIGQgLSBqIC0gMSBdICk7XG5cbiAgICAgICAgICAgICAgICAgICAgciA9IHJtIDwgNFxuICAgICAgICAgICAgICAgICAgICAgID8gKCByZCB8fCByICkgJiYgKCBybSA9PSAwIHx8IHJtID09ICggeC5zIDwgMCA/IDMgOiAyICkgKVxuICAgICAgICAgICAgICAgICAgICAgIDogcmQgPiA1IHx8IHJkID09IDUgJiYgKCBybSA9PSA0IHx8IHIgfHwgcm0gPT0gNiAmJlxuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBDaGVjayB3aGV0aGVyIHRoZSBkaWdpdCB0byB0aGUgbGVmdCBvZiB0aGUgcm91bmRpbmcgZGlnaXQgaXMgb2RkLlxuICAgICAgICAgICAgICAgICAgICAgICAgKCAoIGkgPiAwID8gaiA+IDAgPyBuIC8gcG93czEwWyBkIC0gaiBdIDogMCA6IHhjW25pIC0gMV0gKSAlIDEwICkgJiAxIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgIHJtID09ICggeC5zIDwgMCA/IDggOiA3ICkgKTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoIHNkIDwgMSB8fCAheGNbMF0gKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB4Yy5sZW5ndGggPSAwO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAocikge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ29udmVydCBzZCB0byBkZWNpbWFsIHBsYWNlcy5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZCAtPSB4LmUgKyAxO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gMSwgMC4xLCAwLjAxLCAwLjAwMSwgMC4wMDAxIGV0Yy5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB4Y1swXSA9IHBvd3MxMFsgc2QgJSBMT0dfQkFTRSBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHguZSA9IC1zZCB8fCAwO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFplcm8uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgeGNbMF0gPSB4LmUgPSAwO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4geDtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIFJlbW92ZSBleGNlc3MgZGlnaXRzLlxuICAgICAgICAgICAgICAgICAgICBpZiAoIGkgPT0gMCApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHhjLmxlbmd0aCA9IG5pO1xuICAgICAgICAgICAgICAgICAgICAgICAgayA9IDE7XG4gICAgICAgICAgICAgICAgICAgICAgICBuaS0tO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgeGMubGVuZ3RoID0gbmkgKyAxO1xuICAgICAgICAgICAgICAgICAgICAgICAgayA9IHBvd3MxMFsgTE9HX0JBU0UgLSBpIF07XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEUuZy4gNTY3MDAgYmVjb21lcyA1NjAwMCBpZiA3IGlzIHRoZSByb3VuZGluZyBkaWdpdC5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGogPiAwIG1lYW5zIGkgPiBudW1iZXIgb2YgbGVhZGluZyB6ZXJvcyBvZiBuLlxuICAgICAgICAgICAgICAgICAgICAgICAgeGNbbmldID0gaiA+IDAgPyBtYXRoZmxvb3IoIG4gLyBwb3dzMTBbIGQgLSBqIF0gJSBwb3dzMTBbal0gKSAqIGsgOiAwO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gUm91bmQgdXA/XG4gICAgICAgICAgICAgICAgICAgIGlmIChyKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoIDsgOyApIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIHRoZSBkaWdpdCB0byBiZSByb3VuZGVkIHVwIGlzIGluIHRoZSBmaXJzdCBlbGVtZW50IG9mIHhjLi4uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCBuaSA9PSAwICkge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGkgd2lsbCBiZSB0aGUgbGVuZ3RoIG9mIHhjWzBdIGJlZm9yZSBrIGlzIGFkZGVkLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgKCBpID0gMSwgaiA9IHhjWzBdOyBqID49IDEwOyBqIC89IDEwLCBpKysgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaiA9IHhjWzBdICs9IGs7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoIGsgPSAxOyBqID49IDEwOyBqIC89IDEwLCBrKysgKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpZiBpICE9IGsgdGhlIGxlbmd0aCBoYXMgaW5jcmVhc2VkLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIGkgIT0gayApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHguZSsrO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCB4Y1swXSA9PSBCQVNFICkgeGNbMF0gPSAxO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeGNbbmldICs9IGs7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICggeGNbbmldICE9IEJBU0UgKSBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeGNbbmktLV0gPSAwO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrID0gMTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAvLyBSZW1vdmUgdHJhaWxpbmcgemVyb3MuXG4gICAgICAgICAgICAgICAgICAgIGZvciAoIGkgPSB4Yy5sZW5ndGg7IHhjWy0taV0gPT09IDA7IHhjLnBvcCgpICk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gT3ZlcmZsb3c/IEluZmluaXR5LlxuICAgICAgICAgICAgICAgIGlmICggeC5lID4gTUFYX0VYUCApIHtcbiAgICAgICAgICAgICAgICAgICAgeC5jID0geC5lID0gbnVsbDtcblxuICAgICAgICAgICAgICAgIC8vIFVuZGVyZmxvdz8gWmVyby5cbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCB4LmUgPCBNSU5fRVhQICkge1xuICAgICAgICAgICAgICAgICAgICB4LmMgPSBbIHguZSA9IDAgXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB4O1xuICAgICAgICB9XG5cblxuICAgICAgICAvLyBQUk9UT1RZUEUvSU5TVEFOQ0UgTUVUSE9EU1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIGEgbmV3IEJpZ051bWJlciB3aG9zZSB2YWx1ZSBpcyB0aGUgYWJzb2x1dGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIuXG4gICAgICAgICAqL1xuICAgICAgICBQLmFic29sdXRlVmFsdWUgPSBQLmFicyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciB4ID0gbmV3IEJpZ051bWJlcih0aGlzKTtcbiAgICAgICAgICAgIGlmICggeC5zIDwgMCApIHgucyA9IDE7XG4gICAgICAgICAgICByZXR1cm4geDtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiBhIG5ldyBCaWdOdW1iZXIgd2hvc2UgdmFsdWUgaXMgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIHJvdW5kZWQgdG8gYSB3aG9sZVxuICAgICAgICAgKiBudW1iZXIgaW4gdGhlIGRpcmVjdGlvbiBvZiBJbmZpbml0eS5cbiAgICAgICAgICovXG4gICAgICAgIFAuY2VpbCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiByb3VuZCggbmV3IEJpZ051bWJlcih0aGlzKSwgdGhpcy5lICsgMSwgMiApO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuXG4gICAgICAgICAqIDEgaWYgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIGlzIGdyZWF0ZXIgdGhhbiB0aGUgdmFsdWUgb2YgQmlnTnVtYmVyKHksIGIpLFxuICAgICAgICAgKiAtMSBpZiB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgaXMgbGVzcyB0aGFuIHRoZSB2YWx1ZSBvZiBCaWdOdW1iZXIoeSwgYiksXG4gICAgICAgICAqIDAgaWYgdGhleSBoYXZlIHRoZSBzYW1lIHZhbHVlLFxuICAgICAgICAgKiBvciBudWxsIGlmIHRoZSB2YWx1ZSBvZiBlaXRoZXIgaXMgTmFOLlxuICAgICAgICAgKi9cbiAgICAgICAgUC5jb21wYXJlZFRvID0gUC5jbXAgPSBmdW5jdGlvbiAoIHksIGIgKSB7XG4gICAgICAgICAgICBpZCA9IDE7XG4gICAgICAgICAgICByZXR1cm4gY29tcGFyZSggdGhpcywgbmV3IEJpZ051bWJlciggeSwgYiApICk7XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gdGhlIG51bWJlciBvZiBkZWNpbWFsIHBsYWNlcyBvZiB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIsIG9yIG51bGwgaWYgdGhlIHZhbHVlXG4gICAgICAgICAqIG9mIHRoaXMgQmlnTnVtYmVyIGlzIMKxSW5maW5pdHkgb3IgTmFOLlxuICAgICAgICAgKi9cbiAgICAgICAgUC5kZWNpbWFsUGxhY2VzID0gUC5kcCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBuLCB2LFxuICAgICAgICAgICAgICAgIGMgPSB0aGlzLmM7XG5cbiAgICAgICAgICAgIGlmICggIWMgKSByZXR1cm4gbnVsbDtcbiAgICAgICAgICAgIG4gPSAoICggdiA9IGMubGVuZ3RoIC0gMSApIC0gYml0Rmxvb3IoIHRoaXMuZSAvIExPR19CQVNFICkgKSAqIExPR19CQVNFO1xuXG4gICAgICAgICAgICAvLyBTdWJ0cmFjdCB0aGUgbnVtYmVyIG9mIHRyYWlsaW5nIHplcm9zIG9mIHRoZSBsYXN0IG51bWJlci5cbiAgICAgICAgICAgIGlmICggdiA9IGNbdl0gKSBmb3IgKCA7IHYgJSAxMCA9PSAwOyB2IC89IDEwLCBuLS0gKTtcbiAgICAgICAgICAgIGlmICggbiA8IDAgKSBuID0gMDtcblxuICAgICAgICAgICAgcmV0dXJuIG47XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiAgbiAvIDAgPSBJXG4gICAgICAgICAqICBuIC8gTiA9IE5cbiAgICAgICAgICogIG4gLyBJID0gMFxuICAgICAgICAgKiAgMCAvIG4gPSAwXG4gICAgICAgICAqICAwIC8gMCA9IE5cbiAgICAgICAgICogIDAgLyBOID0gTlxuICAgICAgICAgKiAgMCAvIEkgPSAwXG4gICAgICAgICAqICBOIC8gbiA9IE5cbiAgICAgICAgICogIE4gLyAwID0gTlxuICAgICAgICAgKiAgTiAvIE4gPSBOXG4gICAgICAgICAqICBOIC8gSSA9IE5cbiAgICAgICAgICogIEkgLyBuID0gSVxuICAgICAgICAgKiAgSSAvIDAgPSBJXG4gICAgICAgICAqICBJIC8gTiA9IE5cbiAgICAgICAgICogIEkgLyBJID0gTlxuICAgICAgICAgKlxuICAgICAgICAgKiBSZXR1cm4gYSBuZXcgQmlnTnVtYmVyIHdob3NlIHZhbHVlIGlzIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlciBkaXZpZGVkIGJ5IHRoZSB2YWx1ZSBvZlxuICAgICAgICAgKiBCaWdOdW1iZXIoeSwgYiksIHJvdW5kZWQgYWNjb3JkaW5nIHRvIERFQ0lNQUxfUExBQ0VTIGFuZCBST1VORElOR19NT0RFLlxuICAgICAgICAgKi9cbiAgICAgICAgUC5kaXZpZGVkQnkgPSBQLmRpdiA9IGZ1bmN0aW9uICggeSwgYiApIHtcbiAgICAgICAgICAgIGlkID0gMztcbiAgICAgICAgICAgIHJldHVybiBkaXYoIHRoaXMsIG5ldyBCaWdOdW1iZXIoIHksIGIgKSwgREVDSU1BTF9QTEFDRVMsIFJPVU5ESU5HX01PREUgKTtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiBhIG5ldyBCaWdOdW1iZXIgd2hvc2UgdmFsdWUgaXMgdGhlIGludGVnZXIgcGFydCBvZiBkaXZpZGluZyB0aGUgdmFsdWUgb2YgdGhpc1xuICAgICAgICAgKiBCaWdOdW1iZXIgYnkgdGhlIHZhbHVlIG9mIEJpZ051bWJlcih5LCBiKS5cbiAgICAgICAgICovXG4gICAgICAgIFAuZGl2aWRlZFRvSW50ZWdlckJ5ID0gUC5kaXZUb0ludCA9IGZ1bmN0aW9uICggeSwgYiApIHtcbiAgICAgICAgICAgIGlkID0gNDtcbiAgICAgICAgICAgIHJldHVybiBkaXYoIHRoaXMsIG5ldyBCaWdOdW1iZXIoIHksIGIgKSwgMCwgMSApO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIHRydWUgaWYgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIGlzIGVxdWFsIHRvIHRoZSB2YWx1ZSBvZiBCaWdOdW1iZXIoeSwgYiksXG4gICAgICAgICAqIG90aGVyd2lzZSByZXR1cm5zIGZhbHNlLlxuICAgICAgICAgKi9cbiAgICAgICAgUC5lcXVhbHMgPSBQLmVxID0gZnVuY3Rpb24gKCB5LCBiICkge1xuICAgICAgICAgICAgaWQgPSA1O1xuICAgICAgICAgICAgcmV0dXJuIGNvbXBhcmUoIHRoaXMsIG5ldyBCaWdOdW1iZXIoIHksIGIgKSApID09PSAwO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIGEgbmV3IEJpZ051bWJlciB3aG9zZSB2YWx1ZSBpcyB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgcm91bmRlZCB0byBhIHdob2xlXG4gICAgICAgICAqIG51bWJlciBpbiB0aGUgZGlyZWN0aW9uIG9mIC1JbmZpbml0eS5cbiAgICAgICAgICovXG4gICAgICAgIFAuZmxvb3IgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gcm91bmQoIG5ldyBCaWdOdW1iZXIodGhpcyksIHRoaXMuZSArIDEsIDMgKTtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiB0cnVlIGlmIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlciBpcyBncmVhdGVyIHRoYW4gdGhlIHZhbHVlIG9mIEJpZ051bWJlcih5LCBiKSxcbiAgICAgICAgICogb3RoZXJ3aXNlIHJldHVybnMgZmFsc2UuXG4gICAgICAgICAqL1xuICAgICAgICBQLmdyZWF0ZXJUaGFuID0gUC5ndCA9IGZ1bmN0aW9uICggeSwgYiApIHtcbiAgICAgICAgICAgIGlkID0gNjtcbiAgICAgICAgICAgIHJldHVybiBjb21wYXJlKCB0aGlzLCBuZXcgQmlnTnVtYmVyKCB5LCBiICkgKSA+IDA7XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gdHJ1ZSBpZiB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgaXMgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvIHRoZSB2YWx1ZSBvZlxuICAgICAgICAgKiBCaWdOdW1iZXIoeSwgYiksIG90aGVyd2lzZSByZXR1cm5zIGZhbHNlLlxuICAgICAgICAgKi9cbiAgICAgICAgUC5ncmVhdGVyVGhhbk9yRXF1YWxUbyA9IFAuZ3RlID0gZnVuY3Rpb24gKCB5LCBiICkge1xuICAgICAgICAgICAgaWQgPSA3O1xuICAgICAgICAgICAgcmV0dXJuICggYiA9IGNvbXBhcmUoIHRoaXMsIG5ldyBCaWdOdW1iZXIoIHksIGIgKSApICkgPT09IDEgfHwgYiA9PT0gMDtcblxuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIHRydWUgaWYgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIGlzIGEgZmluaXRlIG51bWJlciwgb3RoZXJ3aXNlIHJldHVybnMgZmFsc2UuXG4gICAgICAgICAqL1xuICAgICAgICBQLmlzRmluaXRlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuICEhdGhpcy5jO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIHRydWUgaWYgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIGlzIGFuIGludGVnZXIsIG90aGVyd2lzZSByZXR1cm4gZmFsc2UuXG4gICAgICAgICAqL1xuICAgICAgICBQLmlzSW50ZWdlciA9IFAuaXNJbnQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gISF0aGlzLmMgJiYgYml0Rmxvb3IoIHRoaXMuZSAvIExPR19CQVNFICkgPiB0aGlzLmMubGVuZ3RoIC0gMjtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiB0cnVlIGlmIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlciBpcyBOYU4sIG90aGVyd2lzZSByZXR1cm5zIGZhbHNlLlxuICAgICAgICAgKi9cbiAgICAgICAgUC5pc05hTiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiAhdGhpcy5zO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIHRydWUgaWYgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIGlzIG5lZ2F0aXZlLCBvdGhlcndpc2UgcmV0dXJucyBmYWxzZS5cbiAgICAgICAgICovXG4gICAgICAgIFAuaXNOZWdhdGl2ZSA9IFAuaXNOZWcgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5zIDwgMDtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiB0cnVlIGlmIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlciBpcyAwIG9yIC0wLCBvdGhlcndpc2UgcmV0dXJucyBmYWxzZS5cbiAgICAgICAgICovXG4gICAgICAgIFAuaXNaZXJvID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuICEhdGhpcy5jICYmIHRoaXMuY1swXSA9PSAwO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIHRydWUgaWYgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIGlzIGxlc3MgdGhhbiB0aGUgdmFsdWUgb2YgQmlnTnVtYmVyKHksIGIpLFxuICAgICAgICAgKiBvdGhlcndpc2UgcmV0dXJucyBmYWxzZS5cbiAgICAgICAgICovXG4gICAgICAgIFAubGVzc1RoYW4gPSBQLmx0ID0gZnVuY3Rpb24gKCB5LCBiICkge1xuICAgICAgICAgICAgaWQgPSA4O1xuICAgICAgICAgICAgcmV0dXJuIGNvbXBhcmUoIHRoaXMsIG5ldyBCaWdOdW1iZXIoIHksIGIgKSApIDwgMDtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiB0cnVlIGlmIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlciBpcyBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gdGhlIHZhbHVlIG9mXG4gICAgICAgICAqIEJpZ051bWJlcih5LCBiKSwgb3RoZXJ3aXNlIHJldHVybnMgZmFsc2UuXG4gICAgICAgICAqL1xuICAgICAgICBQLmxlc3NUaGFuT3JFcXVhbFRvID0gUC5sdGUgPSBmdW5jdGlvbiAoIHksIGIgKSB7XG4gICAgICAgICAgICBpZCA9IDk7XG4gICAgICAgICAgICByZXR1cm4gKCBiID0gY29tcGFyZSggdGhpcywgbmV3IEJpZ051bWJlciggeSwgYiApICkgKSA9PT0gLTEgfHwgYiA9PT0gMDtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqICBuIC0gMCA9IG5cbiAgICAgICAgICogIG4gLSBOID0gTlxuICAgICAgICAgKiAgbiAtIEkgPSAtSVxuICAgICAgICAgKiAgMCAtIG4gPSAtblxuICAgICAgICAgKiAgMCAtIDAgPSAwXG4gICAgICAgICAqICAwIC0gTiA9IE5cbiAgICAgICAgICogIDAgLSBJID0gLUlcbiAgICAgICAgICogIE4gLSBuID0gTlxuICAgICAgICAgKiAgTiAtIDAgPSBOXG4gICAgICAgICAqICBOIC0gTiA9IE5cbiAgICAgICAgICogIE4gLSBJID0gTlxuICAgICAgICAgKiAgSSAtIG4gPSBJXG4gICAgICAgICAqICBJIC0gMCA9IElcbiAgICAgICAgICogIEkgLSBOID0gTlxuICAgICAgICAgKiAgSSAtIEkgPSBOXG4gICAgICAgICAqXG4gICAgICAgICAqIFJldHVybiBhIG5ldyBCaWdOdW1iZXIgd2hvc2UgdmFsdWUgaXMgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIG1pbnVzIHRoZSB2YWx1ZSBvZlxuICAgICAgICAgKiBCaWdOdW1iZXIoeSwgYikuXG4gICAgICAgICAqL1xuICAgICAgICBQLm1pbnVzID0gUC5zdWIgPSBmdW5jdGlvbiAoIHksIGIgKSB7XG4gICAgICAgICAgICB2YXIgaSwgaiwgdCwgeExUeSxcbiAgICAgICAgICAgICAgICB4ID0gdGhpcyxcbiAgICAgICAgICAgICAgICBhID0geC5zO1xuXG4gICAgICAgICAgICBpZCA9IDEwO1xuICAgICAgICAgICAgeSA9IG5ldyBCaWdOdW1iZXIoIHksIGIgKTtcbiAgICAgICAgICAgIGIgPSB5LnM7XG5cbiAgICAgICAgICAgIC8vIEVpdGhlciBOYU4/XG4gICAgICAgICAgICBpZiAoICFhIHx8ICFiICkgcmV0dXJuIG5ldyBCaWdOdW1iZXIoTmFOKTtcblxuICAgICAgICAgICAgLy8gU2lnbnMgZGlmZmVyP1xuICAgICAgICAgICAgaWYgKCBhICE9IGIgKSB7XG4gICAgICAgICAgICAgICAgeS5zID0gLWI7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHgucGx1cyh5KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHhlID0geC5lIC8gTE9HX0JBU0UsXG4gICAgICAgICAgICAgICAgeWUgPSB5LmUgLyBMT0dfQkFTRSxcbiAgICAgICAgICAgICAgICB4YyA9IHguYyxcbiAgICAgICAgICAgICAgICB5YyA9IHkuYztcblxuICAgICAgICAgICAgaWYgKCAheGUgfHwgIXllICkge1xuXG4gICAgICAgICAgICAgICAgLy8gRWl0aGVyIEluZmluaXR5P1xuICAgICAgICAgICAgICAgIGlmICggIXhjIHx8ICF5YyApIHJldHVybiB4YyA/ICggeS5zID0gLWIsIHkgKSA6IG5ldyBCaWdOdW1iZXIoIHljID8geCA6IE5hTiApO1xuXG4gICAgICAgICAgICAgICAgLy8gRWl0aGVyIHplcm8/XG4gICAgICAgICAgICAgICAgaWYgKCAheGNbMF0gfHwgIXljWzBdICkge1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIFJldHVybiB5IGlmIHkgaXMgbm9uLXplcm8sIHggaWYgeCBpcyBub24temVybywgb3IgemVybyBpZiBib3RoIGFyZSB6ZXJvLlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4geWNbMF0gPyAoIHkucyA9IC1iLCB5ICkgOiBuZXcgQmlnTnVtYmVyKCB4Y1swXSA/IHggOlxuXG4gICAgICAgICAgICAgICAgICAgICAgLy8gSUVFRSA3NTQgKDIwMDgpIDYuMzogbiAtIG4gPSAtMCB3aGVuIHJvdW5kaW5nIHRvIC1JbmZpbml0eVxuICAgICAgICAgICAgICAgICAgICAgIFJPVU5ESU5HX01PREUgPT0gMyA/IC0wIDogMCApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgeGUgPSBiaXRGbG9vcih4ZSk7XG4gICAgICAgICAgICB5ZSA9IGJpdEZsb29yKHllKTtcbiAgICAgICAgICAgIHhjID0geGMuc2xpY2UoKTtcblxuICAgICAgICAgICAgLy8gRGV0ZXJtaW5lIHdoaWNoIGlzIHRoZSBiaWdnZXIgbnVtYmVyLlxuICAgICAgICAgICAgaWYgKCBhID0geGUgLSB5ZSApIHtcblxuICAgICAgICAgICAgICAgIGlmICggeExUeSA9IGEgPCAwICkge1xuICAgICAgICAgICAgICAgICAgICBhID0gLWE7XG4gICAgICAgICAgICAgICAgICAgIHQgPSB4YztcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB5ZSA9IHhlO1xuICAgICAgICAgICAgICAgICAgICB0ID0geWM7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdC5yZXZlcnNlKCk7XG5cbiAgICAgICAgICAgICAgICAvLyBQcmVwZW5kIHplcm9zIHRvIGVxdWFsaXNlIGV4cG9uZW50cy5cbiAgICAgICAgICAgICAgICBmb3IgKCBiID0gYTsgYi0tOyB0LnB1c2goMCkgKTtcbiAgICAgICAgICAgICAgICB0LnJldmVyc2UoKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG5cbiAgICAgICAgICAgICAgICAvLyBFeHBvbmVudHMgZXF1YWwuIENoZWNrIGRpZ2l0IGJ5IGRpZ2l0LlxuICAgICAgICAgICAgICAgIGogPSAoIHhMVHkgPSAoIGEgPSB4Yy5sZW5ndGggKSA8ICggYiA9IHljLmxlbmd0aCApICkgPyBhIDogYjtcblxuICAgICAgICAgICAgICAgIGZvciAoIGEgPSBiID0gMDsgYiA8IGo7IGIrKyApIHtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoIHhjW2JdICE9IHljW2JdICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgeExUeSA9IHhjW2JdIDwgeWNbYl07XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8geCA8IHk/IFBvaW50IHhjIHRvIHRoZSBhcnJheSBvZiB0aGUgYmlnZ2VyIG51bWJlci5cbiAgICAgICAgICAgIGlmICh4TFR5KSB0ID0geGMsIHhjID0geWMsIHljID0gdCwgeS5zID0gLXkucztcblxuICAgICAgICAgICAgYiA9ICggaiA9IHljLmxlbmd0aCApIC0gKCBpID0geGMubGVuZ3RoICk7XG5cbiAgICAgICAgICAgIC8vIEFwcGVuZCB6ZXJvcyB0byB4YyBpZiBzaG9ydGVyLlxuICAgICAgICAgICAgLy8gTm8gbmVlZCB0byBhZGQgemVyb3MgdG8geWMgaWYgc2hvcnRlciBhcyBzdWJ0cmFjdCBvbmx5IG5lZWRzIHRvIHN0YXJ0IGF0IHljLmxlbmd0aC5cbiAgICAgICAgICAgIGlmICggYiA+IDAgKSBmb3IgKCA7IGItLTsgeGNbaSsrXSA9IDAgKTtcbiAgICAgICAgICAgIGIgPSBCQVNFIC0gMTtcblxuICAgICAgICAgICAgLy8gU3VidHJhY3QgeWMgZnJvbSB4Yy5cbiAgICAgICAgICAgIGZvciAoIDsgaiA+IGE7ICkge1xuXG4gICAgICAgICAgICAgICAgaWYgKCB4Y1stLWpdIDwgeWNbal0gKSB7XG4gICAgICAgICAgICAgICAgICAgIGZvciAoIGkgPSBqOyBpICYmICF4Y1stLWldOyB4Y1tpXSA9IGIgKTtcbiAgICAgICAgICAgICAgICAgICAgLS14Y1tpXTtcbiAgICAgICAgICAgICAgICAgICAgeGNbal0gKz0gQkFTRTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB4Y1tqXSAtPSB5Y1tqXTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gUmVtb3ZlIGxlYWRpbmcgemVyb3MgYW5kIGFkanVzdCBleHBvbmVudCBhY2NvcmRpbmdseS5cbiAgICAgICAgICAgIGZvciAoIDsgeGNbMF0gPT0gMDsgeGMuc2hpZnQoKSwgLS15ZSApO1xuXG4gICAgICAgICAgICAvLyBaZXJvP1xuICAgICAgICAgICAgaWYgKCAheGNbMF0gKSB7XG5cbiAgICAgICAgICAgICAgICAvLyBGb2xsb3dpbmcgSUVFRSA3NTQgKDIwMDgpIDYuMyxcbiAgICAgICAgICAgICAgICAvLyBuIC0gbiA9ICswICBidXQgIG4gLSBuID0gLTAgIHdoZW4gcm91bmRpbmcgdG93YXJkcyAtSW5maW5pdHkuXG4gICAgICAgICAgICAgICAgeS5zID0gUk9VTkRJTkdfTU9ERSA9PSAzID8gLTEgOiAxO1xuICAgICAgICAgICAgICAgIHkuYyA9IFsgeS5lID0gMCBdO1xuICAgICAgICAgICAgICAgIHJldHVybiB5O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBObyBuZWVkIHRvIGNoZWNrIGZvciBJbmZpbml0eSBhcyAreCAtICt5ICE9IEluZmluaXR5ICYmIC14IC0gLXkgIT0gSW5maW5pdHlcbiAgICAgICAgICAgIC8vIGZvciBmaW5pdGUgeCBhbmQgeS5cbiAgICAgICAgICAgIHJldHVybiBub3JtYWxpc2UoIHksIHhjLCB5ZSApO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogICBuICUgMCA9ICBOXG4gICAgICAgICAqICAgbiAlIE4gPSAgTlxuICAgICAgICAgKiAgIG4gJSBJID0gIG5cbiAgICAgICAgICogICAwICUgbiA9ICAwXG4gICAgICAgICAqICAtMCAlIG4gPSAtMFxuICAgICAgICAgKiAgIDAgJSAwID0gIE5cbiAgICAgICAgICogICAwICUgTiA9ICBOXG4gICAgICAgICAqICAgMCAlIEkgPSAgMFxuICAgICAgICAgKiAgIE4gJSBuID0gIE5cbiAgICAgICAgICogICBOICUgMCA9ICBOXG4gICAgICAgICAqICAgTiAlIE4gPSAgTlxuICAgICAgICAgKiAgIE4gJSBJID0gIE5cbiAgICAgICAgICogICBJICUgbiA9ICBOXG4gICAgICAgICAqICAgSSAlIDAgPSAgTlxuICAgICAgICAgKiAgIEkgJSBOID0gIE5cbiAgICAgICAgICogICBJICUgSSA9ICBOXG4gICAgICAgICAqXG4gICAgICAgICAqIFJldHVybiBhIG5ldyBCaWdOdW1iZXIgd2hvc2UgdmFsdWUgaXMgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIG1vZHVsbyB0aGUgdmFsdWUgb2ZcbiAgICAgICAgICogQmlnTnVtYmVyKHksIGIpLiBUaGUgcmVzdWx0IGRlcGVuZHMgb24gdGhlIHZhbHVlIG9mIE1PRFVMT19NT0RFLlxuICAgICAgICAgKi9cbiAgICAgICAgUC5tb2R1bG8gPSBQLm1vZCA9IGZ1bmN0aW9uICggeSwgYiApIHtcbiAgICAgICAgICAgIHZhciBxLCBzLFxuICAgICAgICAgICAgICAgIHggPSB0aGlzO1xuXG4gICAgICAgICAgICBpZCA9IDExO1xuICAgICAgICAgICAgeSA9IG5ldyBCaWdOdW1iZXIoIHksIGIgKTtcblxuICAgICAgICAgICAgLy8gUmV0dXJuIE5hTiBpZiB4IGlzIEluZmluaXR5IG9yIE5hTiwgb3IgeSBpcyBOYU4gb3IgemVyby5cbiAgICAgICAgICAgIGlmICggIXguYyB8fCAheS5zIHx8IHkuYyAmJiAheS5jWzBdICkge1xuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgQmlnTnVtYmVyKE5hTik7XG5cbiAgICAgICAgICAgIC8vIFJldHVybiB4IGlmIHkgaXMgSW5maW5pdHkgb3IgeCBpcyB6ZXJvLlxuICAgICAgICAgICAgfSBlbHNlIGlmICggIXkuYyB8fCB4LmMgJiYgIXguY1swXSApIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbmV3IEJpZ051bWJlcih4KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCBNT0RVTE9fTU9ERSA9PSA5ICkge1xuXG4gICAgICAgICAgICAgICAgLy8gRXVjbGlkaWFuIGRpdmlzaW9uOiBxID0gc2lnbih5KSAqIGZsb29yKHggLyBhYnMoeSkpXG4gICAgICAgICAgICAgICAgLy8gciA9IHggLSBxeSAgICB3aGVyZSAgMCA8PSByIDwgYWJzKHkpXG4gICAgICAgICAgICAgICAgcyA9IHkucztcbiAgICAgICAgICAgICAgICB5LnMgPSAxO1xuICAgICAgICAgICAgICAgIHEgPSBkaXYoIHgsIHksIDAsIDMgKTtcbiAgICAgICAgICAgICAgICB5LnMgPSBzO1xuICAgICAgICAgICAgICAgIHEucyAqPSBzO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBxID0gZGl2KCB4LCB5LCAwLCBNT0RVTE9fTU9ERSApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4geC5taW51cyggcS50aW1lcyh5KSApO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIGEgbmV3IEJpZ051bWJlciB3aG9zZSB2YWx1ZSBpcyB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgbmVnYXRlZCxcbiAgICAgICAgICogaS5lLiBtdWx0aXBsaWVkIGJ5IC0xLlxuICAgICAgICAgKi9cbiAgICAgICAgUC5uZWdhdGVkID0gUC5uZWcgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgeCA9IG5ldyBCaWdOdW1iZXIodGhpcyk7XG4gICAgICAgICAgICB4LnMgPSAteC5zIHx8IG51bGw7XG4gICAgICAgICAgICByZXR1cm4geDtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqICBuICsgMCA9IG5cbiAgICAgICAgICogIG4gKyBOID0gTlxuICAgICAgICAgKiAgbiArIEkgPSBJXG4gICAgICAgICAqICAwICsgbiA9IG5cbiAgICAgICAgICogIDAgKyAwID0gMFxuICAgICAgICAgKiAgMCArIE4gPSBOXG4gICAgICAgICAqICAwICsgSSA9IElcbiAgICAgICAgICogIE4gKyBuID0gTlxuICAgICAgICAgKiAgTiArIDAgPSBOXG4gICAgICAgICAqICBOICsgTiA9IE5cbiAgICAgICAgICogIE4gKyBJID0gTlxuICAgICAgICAgKiAgSSArIG4gPSBJXG4gICAgICAgICAqICBJICsgMCA9IElcbiAgICAgICAgICogIEkgKyBOID0gTlxuICAgICAgICAgKiAgSSArIEkgPSBJXG4gICAgICAgICAqXG4gICAgICAgICAqIFJldHVybiBhIG5ldyBCaWdOdW1iZXIgd2hvc2UgdmFsdWUgaXMgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIHBsdXMgdGhlIHZhbHVlIG9mXG4gICAgICAgICAqIEJpZ051bWJlcih5LCBiKS5cbiAgICAgICAgICovXG4gICAgICAgIFAucGx1cyA9IFAuYWRkID0gZnVuY3Rpb24gKCB5LCBiICkge1xuICAgICAgICAgICAgdmFyIHQsXG4gICAgICAgICAgICAgICAgeCA9IHRoaXMsXG4gICAgICAgICAgICAgICAgYSA9IHgucztcblxuICAgICAgICAgICAgaWQgPSAxMjtcbiAgICAgICAgICAgIHkgPSBuZXcgQmlnTnVtYmVyKCB5LCBiICk7XG4gICAgICAgICAgICBiID0geS5zO1xuXG4gICAgICAgICAgICAvLyBFaXRoZXIgTmFOP1xuICAgICAgICAgICAgaWYgKCAhYSB8fCAhYiApIHJldHVybiBuZXcgQmlnTnVtYmVyKE5hTik7XG5cbiAgICAgICAgICAgIC8vIFNpZ25zIGRpZmZlcj9cbiAgICAgICAgICAgICBpZiAoIGEgIT0gYiApIHtcbiAgICAgICAgICAgICAgICB5LnMgPSAtYjtcbiAgICAgICAgICAgICAgICByZXR1cm4geC5taW51cyh5KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHhlID0geC5lIC8gTE9HX0JBU0UsXG4gICAgICAgICAgICAgICAgeWUgPSB5LmUgLyBMT0dfQkFTRSxcbiAgICAgICAgICAgICAgICB4YyA9IHguYyxcbiAgICAgICAgICAgICAgICB5YyA9IHkuYztcblxuICAgICAgICAgICAgaWYgKCAheGUgfHwgIXllICkge1xuXG4gICAgICAgICAgICAgICAgLy8gUmV0dXJuIMKxSW5maW5pdHkgaWYgZWl0aGVyIMKxSW5maW5pdHkuXG4gICAgICAgICAgICAgICAgaWYgKCAheGMgfHwgIXljICkgcmV0dXJuIG5ldyBCaWdOdW1iZXIoIGEgLyAwICk7XG5cbiAgICAgICAgICAgICAgICAvLyBFaXRoZXIgemVybz9cbiAgICAgICAgICAgICAgICAvLyBSZXR1cm4geSBpZiB5IGlzIG5vbi16ZXJvLCB4IGlmIHggaXMgbm9uLXplcm8sIG9yIHplcm8gaWYgYm90aCBhcmUgemVyby5cbiAgICAgICAgICAgICAgICBpZiAoICF4Y1swXSB8fCAheWNbMF0gKSByZXR1cm4geWNbMF0gPyB5IDogbmV3IEJpZ051bWJlciggeGNbMF0gPyB4IDogYSAqIDAgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgeGUgPSBiaXRGbG9vcih4ZSk7XG4gICAgICAgICAgICB5ZSA9IGJpdEZsb29yKHllKTtcbiAgICAgICAgICAgIHhjID0geGMuc2xpY2UoKTtcblxuICAgICAgICAgICAgLy8gUHJlcGVuZCB6ZXJvcyB0byBlcXVhbGlzZSBleHBvbmVudHMuIEZhc3RlciB0byB1c2UgcmV2ZXJzZSB0aGVuIGRvIHVuc2hpZnRzLlxuICAgICAgICAgICAgaWYgKCBhID0geGUgLSB5ZSApIHtcbiAgICAgICAgICAgICAgICBpZiAoIGEgPiAwICkge1xuICAgICAgICAgICAgICAgICAgICB5ZSA9IHhlO1xuICAgICAgICAgICAgICAgICAgICB0ID0geWM7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgYSA9IC1hO1xuICAgICAgICAgICAgICAgICAgICB0ID0geGM7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdC5yZXZlcnNlKCk7XG4gICAgICAgICAgICAgICAgZm9yICggOyBhLS07IHQucHVzaCgwKSApO1xuICAgICAgICAgICAgICAgIHQucmV2ZXJzZSgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBhID0geGMubGVuZ3RoO1xuICAgICAgICAgICAgYiA9IHljLmxlbmd0aDtcblxuICAgICAgICAgICAgLy8gUG9pbnQgeGMgdG8gdGhlIGxvbmdlciBhcnJheSwgYW5kIGIgdG8gdGhlIHNob3J0ZXIgbGVuZ3RoLlxuICAgICAgICAgICAgaWYgKCBhIC0gYiA8IDAgKSB0ID0geWMsIHljID0geGMsIHhjID0gdCwgYiA9IGE7XG5cbiAgICAgICAgICAgIC8vIE9ubHkgc3RhcnQgYWRkaW5nIGF0IHljLmxlbmd0aCAtIDEgYXMgdGhlIGZ1cnRoZXIgZGlnaXRzIG9mIHhjIGNhbiBiZSBpZ25vcmVkLlxuICAgICAgICAgICAgZm9yICggYSA9IDA7IGI7ICkge1xuICAgICAgICAgICAgICAgIGEgPSAoIHhjWy0tYl0gPSB4Y1tiXSArIHljW2JdICsgYSApIC8gQkFTRSB8IDA7XG4gICAgICAgICAgICAgICAgeGNbYl0gJT0gQkFTRTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGEpIHtcbiAgICAgICAgICAgICAgICB4Yy51bnNoaWZ0KGEpO1xuICAgICAgICAgICAgICAgICsreWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIE5vIG5lZWQgdG8gY2hlY2sgZm9yIHplcm8sIGFzICt4ICsgK3kgIT0gMCAmJiAteCArIC15ICE9IDBcbiAgICAgICAgICAgIC8vIHllID0gTUFYX0VYUCArIDEgcG9zc2libGVcbiAgICAgICAgICAgIHJldHVybiBub3JtYWxpc2UoIHksIHhjLCB5ZSApO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIHRoZSBudW1iZXIgb2Ygc2lnbmlmaWNhbnQgZGlnaXRzIG9mIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlci5cbiAgICAgICAgICpcbiAgICAgICAgICogW3pdIHtib29sZWFufG51bWJlcn0gV2hldGhlciB0byBjb3VudCBpbnRlZ2VyLXBhcnQgdHJhaWxpbmcgemVyb3M6IHRydWUsIGZhbHNlLCAxIG9yIDAuXG4gICAgICAgICAqL1xuICAgICAgICBQLnByZWNpc2lvbiA9IFAuc2QgPSBmdW5jdGlvbiAoeikge1xuICAgICAgICAgICAgdmFyIG4sIHYsXG4gICAgICAgICAgICAgICAgeCA9IHRoaXMsXG4gICAgICAgICAgICAgICAgYyA9IHguYztcblxuICAgICAgICAgICAgLy8gJ3ByZWNpc2lvbigpIGFyZ3VtZW50IG5vdCBhIGJvb2xlYW4gb3IgYmluYXJ5IGRpZ2l0OiB7en0nXG4gICAgICAgICAgICBpZiAoIHogIT0gbnVsbCAmJiB6ICE9PSAhIXogJiYgeiAhPT0gMSAmJiB6ICE9PSAwICkge1xuICAgICAgICAgICAgICAgIGlmIChFUlJPUlMpIHJhaXNlKCAxMywgJ2FyZ3VtZW50JyArIG5vdEJvb2wsIHogKTtcbiAgICAgICAgICAgICAgICBpZiAoIHogIT0gISF6ICkgeiA9IG51bGw7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICggIWMgKSByZXR1cm4gbnVsbDtcbiAgICAgICAgICAgIHYgPSBjLmxlbmd0aCAtIDE7XG4gICAgICAgICAgICBuID0gdiAqIExPR19CQVNFICsgMTtcblxuICAgICAgICAgICAgaWYgKCB2ID0gY1t2XSApIHtcblxuICAgICAgICAgICAgICAgIC8vIFN1YnRyYWN0IHRoZSBudW1iZXIgb2YgdHJhaWxpbmcgemVyb3Mgb2YgdGhlIGxhc3QgZWxlbWVudC5cbiAgICAgICAgICAgICAgICBmb3IgKCA7IHYgJSAxMCA9PSAwOyB2IC89IDEwLCBuLS0gKTtcblxuICAgICAgICAgICAgICAgIC8vIEFkZCB0aGUgbnVtYmVyIG9mIGRpZ2l0cyBvZiB0aGUgZmlyc3QgZWxlbWVudC5cbiAgICAgICAgICAgICAgICBmb3IgKCB2ID0gY1swXTsgdiA+PSAxMDsgdiAvPSAxMCwgbisrICk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICggeiAmJiB4LmUgKyAxID4gbiApIG4gPSB4LmUgKyAxO1xuXG4gICAgICAgICAgICByZXR1cm4gbjtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiBhIG5ldyBCaWdOdW1iZXIgd2hvc2UgdmFsdWUgaXMgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIHJvdW5kZWQgdG8gYSBtYXhpbXVtIG9mXG4gICAgICAgICAqIGRwIGRlY2ltYWwgcGxhY2VzIHVzaW5nIHJvdW5kaW5nIG1vZGUgcm0sIG9yIHRvIDAgYW5kIFJPVU5ESU5HX01PREUgcmVzcGVjdGl2ZWx5IGlmXG4gICAgICAgICAqIG9taXR0ZWQuXG4gICAgICAgICAqXG4gICAgICAgICAqIFtkcF0ge251bWJlcn0gRGVjaW1hbCBwbGFjZXMuIEludGVnZXIsIDAgdG8gTUFYIGluY2x1c2l2ZS5cbiAgICAgICAgICogW3JtXSB7bnVtYmVyfSBSb3VuZGluZyBtb2RlLiBJbnRlZ2VyLCAwIHRvIDggaW5jbHVzaXZlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAncm91bmQoKSBkZWNpbWFsIHBsYWNlcyBvdXQgb2YgcmFuZ2U6IHtkcH0nXG4gICAgICAgICAqICdyb3VuZCgpIGRlY2ltYWwgcGxhY2VzIG5vdCBhbiBpbnRlZ2VyOiB7ZHB9J1xuICAgICAgICAgKiAncm91bmQoKSByb3VuZGluZyBtb2RlIG5vdCBhbiBpbnRlZ2VyOiB7cm19J1xuICAgICAgICAgKiAncm91bmQoKSByb3VuZGluZyBtb2RlIG91dCBvZiByYW5nZToge3JtfSdcbiAgICAgICAgICovXG4gICAgICAgIFAucm91bmQgPSBmdW5jdGlvbiAoIGRwLCBybSApIHtcbiAgICAgICAgICAgIHZhciBuID0gbmV3IEJpZ051bWJlcih0aGlzKTtcblxuICAgICAgICAgICAgaWYgKCBkcCA9PSBudWxsIHx8IGlzVmFsaWRJbnQoIGRwLCAwLCBNQVgsIDE1ICkgKSB7XG4gICAgICAgICAgICAgICAgcm91bmQoIG4sIH5+ZHAgKyB0aGlzLmUgKyAxLCBybSA9PSBudWxsIHx8XG4gICAgICAgICAgICAgICAgICAhaXNWYWxpZEludCggcm0sIDAsIDgsIDE1LCByb3VuZGluZ01vZGUgKSA/IFJPVU5ESU5HX01PREUgOiBybSB8IDAgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIG47XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gYSBuZXcgQmlnTnVtYmVyIHdob3NlIHZhbHVlIGlzIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlciBzaGlmdGVkIGJ5IGsgcGxhY2VzXG4gICAgICAgICAqIChwb3dlcnMgb2YgMTApLiBTaGlmdCB0byB0aGUgcmlnaHQgaWYgbiA+IDAsIGFuZCB0byB0aGUgbGVmdCBpZiBuIDwgMC5cbiAgICAgICAgICpcbiAgICAgICAgICogayB7bnVtYmVyfSBJbnRlZ2VyLCAtTUFYX1NBRkVfSU5URUdFUiB0byBNQVhfU0FGRV9JTlRFR0VSIGluY2x1c2l2ZS5cbiAgICAgICAgICpcbiAgICAgICAgICogSWYgayBpcyBvdXQgb2YgcmFuZ2UgYW5kIEVSUk9SUyBpcyBmYWxzZSwgdGhlIHJlc3VsdCB3aWxsIGJlIMKxMCBpZiBrIDwgMCwgb3IgwrFJbmZpbml0eVxuICAgICAgICAgKiBvdGhlcndpc2UuXG4gICAgICAgICAqXG4gICAgICAgICAqICdzaGlmdCgpIGFyZ3VtZW50IG5vdCBhbiBpbnRlZ2VyOiB7a30nXG4gICAgICAgICAqICdzaGlmdCgpIGFyZ3VtZW50IG91dCBvZiByYW5nZToge2t9J1xuICAgICAgICAgKi9cbiAgICAgICAgUC5zaGlmdCA9IGZ1bmN0aW9uIChrKSB7XG4gICAgICAgICAgICB2YXIgbiA9IHRoaXM7XG4gICAgICAgICAgICByZXR1cm4gaXNWYWxpZEludCggaywgLU1BWF9TQUZFX0lOVEVHRVIsIE1BWF9TQUZFX0lOVEVHRVIsIDE2LCAnYXJndW1lbnQnIClcblxuICAgICAgICAgICAgICAvLyBrIDwgMWUrMjEsIG9yIHRydW5jYXRlKGspIHdpbGwgcHJvZHVjZSBleHBvbmVudGlhbCBub3RhdGlvbi5cbiAgICAgICAgICAgICAgPyBuLnRpbWVzKCAnMWUnICsgdHJ1bmNhdGUoaykgKVxuICAgICAgICAgICAgICA6IG5ldyBCaWdOdW1iZXIoIG4uYyAmJiBuLmNbMF0gJiYgKCBrIDwgLU1BWF9TQUZFX0lOVEVHRVIgfHwgayA+IE1BWF9TQUZFX0lOVEVHRVIgKVxuICAgICAgICAgICAgICAgID8gbi5zICogKCBrIDwgMCA/IDAgOiAxIC8gMCApXG4gICAgICAgICAgICAgICAgOiBuICk7XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiAgc3FydCgtbikgPSAgTlxuICAgICAgICAgKiAgc3FydCggTikgPSAgTlxuICAgICAgICAgKiAgc3FydCgtSSkgPSAgTlxuICAgICAgICAgKiAgc3FydCggSSkgPSAgSVxuICAgICAgICAgKiAgc3FydCggMCkgPSAgMFxuICAgICAgICAgKiAgc3FydCgtMCkgPSAtMFxuICAgICAgICAgKlxuICAgICAgICAgKiBSZXR1cm4gYSBuZXcgQmlnTnVtYmVyIHdob3NlIHZhbHVlIGlzIHRoZSBzcXVhcmUgcm9vdCBvZiB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIsXG4gICAgICAgICAqIHJvdW5kZWQgYWNjb3JkaW5nIHRvIERFQ0lNQUxfUExBQ0VTIGFuZCBST1VORElOR19NT0RFLlxuICAgICAgICAgKi9cbiAgICAgICAgUC5zcXVhcmVSb290ID0gUC5zcXJ0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIG0sIG4sIHIsIHJlcCwgdCxcbiAgICAgICAgICAgICAgICB4ID0gdGhpcyxcbiAgICAgICAgICAgICAgICBjID0geC5jLFxuICAgICAgICAgICAgICAgIHMgPSB4LnMsXG4gICAgICAgICAgICAgICAgZSA9IHguZSxcbiAgICAgICAgICAgICAgICBkcCA9IERFQ0lNQUxfUExBQ0VTICsgNCxcbiAgICAgICAgICAgICAgICBoYWxmID0gbmV3IEJpZ051bWJlcignMC41Jyk7XG5cbiAgICAgICAgICAgIC8vIE5lZ2F0aXZlL05hTi9JbmZpbml0eS96ZXJvP1xuICAgICAgICAgICAgaWYgKCBzICE9PSAxIHx8ICFjIHx8ICFjWzBdICkge1xuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgQmlnTnVtYmVyKCAhcyB8fCBzIDwgMCAmJiAoICFjIHx8IGNbMF0gKSA/IE5hTiA6IGMgPyB4IDogMSAvIDAgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gSW5pdGlhbCBlc3RpbWF0ZS5cbiAgICAgICAgICAgIHMgPSBNYXRoLnNxcnQoICt4ICk7XG5cbiAgICAgICAgICAgIC8vIE1hdGguc3FydCB1bmRlcmZsb3cvb3ZlcmZsb3c/XG4gICAgICAgICAgICAvLyBQYXNzIHggdG8gTWF0aC5zcXJ0IGFzIGludGVnZXIsIHRoZW4gYWRqdXN0IHRoZSBleHBvbmVudCBvZiB0aGUgcmVzdWx0LlxuICAgICAgICAgICAgaWYgKCBzID09IDAgfHwgcyA9PSAxIC8gMCApIHtcbiAgICAgICAgICAgICAgICBuID0gY29lZmZUb1N0cmluZyhjKTtcbiAgICAgICAgICAgICAgICBpZiAoICggbi5sZW5ndGggKyBlICkgJSAyID09IDAgKSBuICs9ICcwJztcbiAgICAgICAgICAgICAgICBzID0gTWF0aC5zcXJ0KG4pO1xuICAgICAgICAgICAgICAgIGUgPSBiaXRGbG9vciggKCBlICsgMSApIC8gMiApIC0gKCBlIDwgMCB8fCBlICUgMiApO1xuXG4gICAgICAgICAgICAgICAgaWYgKCBzID09IDEgLyAwICkge1xuICAgICAgICAgICAgICAgICAgICBuID0gJzFlJyArIGU7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgbiA9IHMudG9FeHBvbmVudGlhbCgpO1xuICAgICAgICAgICAgICAgICAgICBuID0gbi5zbGljZSggMCwgbi5pbmRleE9mKCdlJykgKyAxICkgKyBlO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHIgPSBuZXcgQmlnTnVtYmVyKG4pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByID0gbmV3IEJpZ051bWJlciggcyArICcnICk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIENoZWNrIGZvciB6ZXJvLlxuICAgICAgICAgICAgLy8gciBjb3VsZCBiZSB6ZXJvIGlmIE1JTl9FWFAgaXMgY2hhbmdlZCBhZnRlciB0aGUgdGhpcyB2YWx1ZSB3YXMgY3JlYXRlZC5cbiAgICAgICAgICAgIC8vIFRoaXMgd291bGQgY2F1c2UgYSBkaXZpc2lvbiBieSB6ZXJvICh4L3QpIGFuZCBoZW5jZSBJbmZpbml0eSBiZWxvdywgd2hpY2ggd291bGQgY2F1c2VcbiAgICAgICAgICAgIC8vIGNvZWZmVG9TdHJpbmcgdG8gdGhyb3cuXG4gICAgICAgICAgICBpZiAoIHIuY1swXSApIHtcbiAgICAgICAgICAgICAgICBlID0gci5lO1xuICAgICAgICAgICAgICAgIHMgPSBlICsgZHA7XG4gICAgICAgICAgICAgICAgaWYgKCBzIDwgMyApIHMgPSAwO1xuXG4gICAgICAgICAgICAgICAgLy8gTmV3dG9uLVJhcGhzb24gaXRlcmF0aW9uLlxuICAgICAgICAgICAgICAgIGZvciAoIDsgOyApIHtcbiAgICAgICAgICAgICAgICAgICAgdCA9IHI7XG4gICAgICAgICAgICAgICAgICAgIHIgPSBoYWxmLnRpbWVzKCB0LnBsdXMoIGRpdiggeCwgdCwgZHAsIDEgKSApICk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCBjb2VmZlRvU3RyaW5nKCB0LmMgICApLnNsaWNlKCAwLCBzICkgPT09ICggbiA9XG4gICAgICAgICAgICAgICAgICAgICAgICAgY29lZmZUb1N0cmluZyggci5jICkgKS5zbGljZSggMCwgcyApICkge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBUaGUgZXhwb25lbnQgb2YgciBtYXkgaGVyZSBiZSBvbmUgbGVzcyB0aGFuIHRoZSBmaW5hbCByZXN1bHQgZXhwb25lbnQsXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBlLmcgMC4wMDA5OTk5IChlLTQpIC0tPiAwLjAwMSAoZS0zKSwgc28gYWRqdXN0IHMgc28gdGhlIHJvdW5kaW5nIGRpZ2l0c1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYXJlIGluZGV4ZWQgY29ycmVjdGx5LlxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCByLmUgPCBlICkgLS1zO1xuICAgICAgICAgICAgICAgICAgICAgICAgbiA9IG4uc2xpY2UoIHMgLSAzLCBzICsgMSApO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBUaGUgNHRoIHJvdW5kaW5nIGRpZ2l0IG1heSBiZSBpbiBlcnJvciBieSAtMSBzbyBpZiB0aGUgNCByb3VuZGluZyBkaWdpdHNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFyZSA5OTk5IG9yIDQ5OTkgKGkuZS4gYXBwcm9hY2hpbmcgYSByb3VuZGluZyBib3VuZGFyeSkgY29udGludWUgdGhlXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBpdGVyYXRpb24uXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIG4gPT0gJzk5OTknIHx8ICFyZXAgJiYgbiA9PSAnNDk5OScgKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBPbiB0aGUgZmlyc3QgaXRlcmF0aW9uIG9ubHksIGNoZWNrIHRvIHNlZSBpZiByb3VuZGluZyB1cCBnaXZlcyB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBleGFjdCByZXN1bHQgYXMgdGhlIG5pbmVzIG1heSBpbmZpbml0ZWx5IHJlcGVhdC5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoICFyZXAgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvdW5kKCB0LCB0LmUgKyBERUNJTUFMX1BMQUNFUyArIDIsIDAgKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIHQudGltZXModCkuZXEoeCkgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByID0gdDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZHAgKz0gNDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzICs9IDQ7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwID0gMTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJZiByb3VuZGluZyBkaWdpdHMgYXJlIG51bGwsIDB7MCw0fSBvciA1MHswLDN9LCBjaGVjayBmb3IgZXhhY3RcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyByZXN1bHQuIElmIG5vdCwgdGhlbiB0aGVyZSBhcmUgZnVydGhlciBkaWdpdHMgYW5kIG0gd2lsbCBiZSB0cnV0aHkuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCAhK24gfHwgIStuLnNsaWNlKDEpICYmIG4uY2hhckF0KDApID09ICc1JyApIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBUcnVuY2F0ZSB0byB0aGUgZmlyc3Qgcm91bmRpbmcgZGlnaXQuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvdW5kKCByLCByLmUgKyBERUNJTUFMX1BMQUNFUyArIDIsIDEgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbSA9ICFyLnRpbWVzKHIpLmVxKHgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gcm91bmQoIHIsIHIuZSArIERFQ0lNQUxfUExBQ0VTICsgMSwgUk9VTkRJTkdfTU9ERSwgbSApO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogIG4gKiAwID0gMFxuICAgICAgICAgKiAgbiAqIE4gPSBOXG4gICAgICAgICAqICBuICogSSA9IElcbiAgICAgICAgICogIDAgKiBuID0gMFxuICAgICAgICAgKiAgMCAqIDAgPSAwXG4gICAgICAgICAqICAwICogTiA9IE5cbiAgICAgICAgICogIDAgKiBJID0gTlxuICAgICAgICAgKiAgTiAqIG4gPSBOXG4gICAgICAgICAqICBOICogMCA9IE5cbiAgICAgICAgICogIE4gKiBOID0gTlxuICAgICAgICAgKiAgTiAqIEkgPSBOXG4gICAgICAgICAqICBJICogbiA9IElcbiAgICAgICAgICogIEkgKiAwID0gTlxuICAgICAgICAgKiAgSSAqIE4gPSBOXG4gICAgICAgICAqICBJICogSSA9IElcbiAgICAgICAgICpcbiAgICAgICAgICogUmV0dXJuIGEgbmV3IEJpZ051bWJlciB3aG9zZSB2YWx1ZSBpcyB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgdGltZXMgdGhlIHZhbHVlIG9mXG4gICAgICAgICAqIEJpZ051bWJlcih5LCBiKS5cbiAgICAgICAgICovXG4gICAgICAgIFAudGltZXMgPSBQLm11bCA9IGZ1bmN0aW9uICggeSwgYiApIHtcbiAgICAgICAgICAgIHZhciBjLCBlLCBpLCBqLCBrLCBtLCB4Y0wsIHhsbywgeGhpLCB5Y0wsIHlsbywgeWhpLCB6YyxcbiAgICAgICAgICAgICAgICBiYXNlLCBzcXJ0QmFzZSxcbiAgICAgICAgICAgICAgICB4ID0gdGhpcyxcbiAgICAgICAgICAgICAgICB4YyA9IHguYyxcbiAgICAgICAgICAgICAgICB5YyA9ICggaWQgPSAxNywgeSA9IG5ldyBCaWdOdW1iZXIoIHksIGIgKSApLmM7XG5cbiAgICAgICAgICAgIC8vIEVpdGhlciBOYU4sIMKxSW5maW5pdHkgb3IgwrEwP1xuICAgICAgICAgICAgaWYgKCAheGMgfHwgIXljIHx8ICF4Y1swXSB8fCAheWNbMF0gKSB7XG5cbiAgICAgICAgICAgICAgICAvLyBSZXR1cm4gTmFOIGlmIGVpdGhlciBpcyBOYU4sIG9yIG9uZSBpcyAwIGFuZCB0aGUgb3RoZXIgaXMgSW5maW5pdHkuXG4gICAgICAgICAgICAgICAgaWYgKCAheC5zIHx8ICF5LnMgfHwgeGMgJiYgIXhjWzBdICYmICF5YyB8fCB5YyAmJiAheWNbMF0gJiYgIXhjICkge1xuICAgICAgICAgICAgICAgICAgICB5LmMgPSB5LmUgPSB5LnMgPSBudWxsO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHkucyAqPSB4LnM7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gUmV0dXJuIMKxSW5maW5pdHkgaWYgZWl0aGVyIGlzIMKxSW5maW5pdHkuXG4gICAgICAgICAgICAgICAgICAgIGlmICggIXhjIHx8ICF5YyApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHkuYyA9IHkuZSA9IG51bGw7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gUmV0dXJuIMKxMCBpZiBlaXRoZXIgaXMgwrEwLlxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgeS5jID0gWzBdO1xuICAgICAgICAgICAgICAgICAgICAgICAgeS5lID0gMDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiB5O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBlID0gYml0Rmxvb3IoIHguZSAvIExPR19CQVNFICkgKyBiaXRGbG9vciggeS5lIC8gTE9HX0JBU0UgKTtcbiAgICAgICAgICAgIHkucyAqPSB4LnM7XG4gICAgICAgICAgICB4Y0wgPSB4Yy5sZW5ndGg7XG4gICAgICAgICAgICB5Y0wgPSB5Yy5sZW5ndGg7XG5cbiAgICAgICAgICAgIC8vIEVuc3VyZSB4YyBwb2ludHMgdG8gbG9uZ2VyIGFycmF5IGFuZCB4Y0wgdG8gaXRzIGxlbmd0aC5cbiAgICAgICAgICAgIGlmICggeGNMIDwgeWNMICkgemMgPSB4YywgeGMgPSB5YywgeWMgPSB6YywgaSA9IHhjTCwgeGNMID0geWNMLCB5Y0wgPSBpO1xuXG4gICAgICAgICAgICAvLyBJbml0aWFsaXNlIHRoZSByZXN1bHQgYXJyYXkgd2l0aCB6ZXJvcy5cbiAgICAgICAgICAgIGZvciAoIGkgPSB4Y0wgKyB5Y0wsIHpjID0gW107IGktLTsgemMucHVzaCgwKSApO1xuXG4gICAgICAgICAgICBiYXNlID0gQkFTRTtcbiAgICAgICAgICAgIHNxcnRCYXNlID0gU1FSVF9CQVNFO1xuXG4gICAgICAgICAgICBmb3IgKCBpID0geWNMOyAtLWkgPj0gMDsgKSB7XG4gICAgICAgICAgICAgICAgYyA9IDA7XG4gICAgICAgICAgICAgICAgeWxvID0geWNbaV0gJSBzcXJ0QmFzZTtcbiAgICAgICAgICAgICAgICB5aGkgPSB5Y1tpXSAvIHNxcnRCYXNlIHwgMDtcblxuICAgICAgICAgICAgICAgIGZvciAoIGsgPSB4Y0wsIGogPSBpICsgazsgaiA+IGk7ICkge1xuICAgICAgICAgICAgICAgICAgICB4bG8gPSB4Y1stLWtdICUgc3FydEJhc2U7XG4gICAgICAgICAgICAgICAgICAgIHhoaSA9IHhjW2tdIC8gc3FydEJhc2UgfCAwO1xuICAgICAgICAgICAgICAgICAgICBtID0geWhpICogeGxvICsgeGhpICogeWxvO1xuICAgICAgICAgICAgICAgICAgICB4bG8gPSB5bG8gKiB4bG8gKyAoICggbSAlIHNxcnRCYXNlICkgKiBzcXJ0QmFzZSApICsgemNbal0gKyBjO1xuICAgICAgICAgICAgICAgICAgICBjID0gKCB4bG8gLyBiYXNlIHwgMCApICsgKCBtIC8gc3FydEJhc2UgfCAwICkgKyB5aGkgKiB4aGk7XG4gICAgICAgICAgICAgICAgICAgIHpjW2otLV0gPSB4bG8gJSBiYXNlO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHpjW2pdID0gYztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGMpIHtcbiAgICAgICAgICAgICAgICArK2U7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHpjLnNoaWZ0KCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBub3JtYWxpc2UoIHksIHpjLCBlICk7XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gYSBuZXcgQmlnTnVtYmVyIHdob3NlIHZhbHVlIGlzIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlciByb3VuZGVkIHRvIGEgbWF4aW11bSBvZlxuICAgICAgICAgKiBzZCBzaWduaWZpY2FudCBkaWdpdHMgdXNpbmcgcm91bmRpbmcgbW9kZSBybSwgb3IgUk9VTkRJTkdfTU9ERSBpZiBybSBpcyBvbWl0dGVkLlxuICAgICAgICAgKlxuICAgICAgICAgKiBbc2RdIHtudW1iZXJ9IFNpZ25pZmljYW50IGRpZ2l0cy4gSW50ZWdlciwgMSB0byBNQVggaW5jbHVzaXZlLlxuICAgICAgICAgKiBbcm1dIHtudW1iZXJ9IFJvdW5kaW5nIG1vZGUuIEludGVnZXIsIDAgdG8gOCBpbmNsdXNpdmUuXG4gICAgICAgICAqXG4gICAgICAgICAqICd0b0RpZ2l0cygpIHByZWNpc2lvbiBvdXQgb2YgcmFuZ2U6IHtzZH0nXG4gICAgICAgICAqICd0b0RpZ2l0cygpIHByZWNpc2lvbiBub3QgYW4gaW50ZWdlcjoge3NkfSdcbiAgICAgICAgICogJ3RvRGlnaXRzKCkgcm91bmRpbmcgbW9kZSBub3QgYW4gaW50ZWdlcjoge3JtfSdcbiAgICAgICAgICogJ3RvRGlnaXRzKCkgcm91bmRpbmcgbW9kZSBvdXQgb2YgcmFuZ2U6IHtybX0nXG4gICAgICAgICAqL1xuICAgICAgICBQLnRvRGlnaXRzID0gZnVuY3Rpb24gKCBzZCwgcm0gKSB7XG4gICAgICAgICAgICB2YXIgbiA9IG5ldyBCaWdOdW1iZXIodGhpcyk7XG4gICAgICAgICAgICBzZCA9IHNkID09IG51bGwgfHwgIWlzVmFsaWRJbnQoIHNkLCAxLCBNQVgsIDE4LCAncHJlY2lzaW9uJyApID8gbnVsbCA6IHNkIHwgMDtcbiAgICAgICAgICAgIHJtID0gcm0gPT0gbnVsbCB8fCAhaXNWYWxpZEludCggcm0sIDAsIDgsIDE4LCByb3VuZGluZ01vZGUgKSA/IFJPVU5ESU5HX01PREUgOiBybSB8IDA7XG4gICAgICAgICAgICByZXR1cm4gc2QgPyByb3VuZCggbiwgc2QsIHJtICkgOiBuO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIGEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgaW4gZXhwb25lbnRpYWwgbm90YXRpb24gYW5kXG4gICAgICAgICAqIHJvdW5kZWQgdXNpbmcgUk9VTkRJTkdfTU9ERSB0byBkcCBmaXhlZCBkZWNpbWFsIHBsYWNlcy5cbiAgICAgICAgICpcbiAgICAgICAgICogW2RwXSB7bnVtYmVyfSBEZWNpbWFsIHBsYWNlcy4gSW50ZWdlciwgMCB0byBNQVggaW5jbHVzaXZlLlxuICAgICAgICAgKiBbcm1dIHtudW1iZXJ9IFJvdW5kaW5nIG1vZGUuIEludGVnZXIsIDAgdG8gOCBpbmNsdXNpdmUuXG4gICAgICAgICAqXG4gICAgICAgICAqICd0b0V4cG9uZW50aWFsKCkgZGVjaW1hbCBwbGFjZXMgbm90IGFuIGludGVnZXI6IHtkcH0nXG4gICAgICAgICAqICd0b0V4cG9uZW50aWFsKCkgZGVjaW1hbCBwbGFjZXMgb3V0IG9mIHJhbmdlOiB7ZHB9J1xuICAgICAgICAgKiAndG9FeHBvbmVudGlhbCgpIHJvdW5kaW5nIG1vZGUgbm90IGFuIGludGVnZXI6IHtybX0nXG4gICAgICAgICAqICd0b0V4cG9uZW50aWFsKCkgcm91bmRpbmcgbW9kZSBvdXQgb2YgcmFuZ2U6IHtybX0nXG4gICAgICAgICAqL1xuICAgICAgICBQLnRvRXhwb25lbnRpYWwgPSBmdW5jdGlvbiAoIGRwLCBybSApIHtcbiAgICAgICAgICAgIHJldHVybiBmb3JtYXQoIHRoaXMsXG4gICAgICAgICAgICAgIGRwICE9IG51bGwgJiYgaXNWYWxpZEludCggZHAsIDAsIE1BWCwgMTkgKSA/IH5+ZHAgKyAxIDogbnVsbCwgcm0sIDE5ICk7XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gYSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlciBpbiBmaXhlZC1wb2ludCBub3RhdGlvbiByb3VuZGluZ1xuICAgICAgICAgKiB0byBkcCBmaXhlZCBkZWNpbWFsIHBsYWNlcyB1c2luZyByb3VuZGluZyBtb2RlIHJtLCBvciBST1VORElOR19NT0RFIGlmIHJtIGlzIG9taXR0ZWQuXG4gICAgICAgICAqXG4gICAgICAgICAqIE5vdGU6IGFzIHdpdGggSmF2YVNjcmlwdCdzIG51bWJlciB0eXBlLCAoLTApLnRvRml4ZWQoMCkgaXMgJzAnLFxuICAgICAgICAgKiBidXQgZS5nLiAoLTAuMDAwMDEpLnRvRml4ZWQoMCkgaXMgJy0wJy5cbiAgICAgICAgICpcbiAgICAgICAgICogW2RwXSB7bnVtYmVyfSBEZWNpbWFsIHBsYWNlcy4gSW50ZWdlciwgMCB0byBNQVggaW5jbHVzaXZlLlxuICAgICAgICAgKiBbcm1dIHtudW1iZXJ9IFJvdW5kaW5nIG1vZGUuIEludGVnZXIsIDAgdG8gOCBpbmNsdXNpdmUuXG4gICAgICAgICAqXG4gICAgICAgICAqICd0b0ZpeGVkKCkgZGVjaW1hbCBwbGFjZXMgbm90IGFuIGludGVnZXI6IHtkcH0nXG4gICAgICAgICAqICd0b0ZpeGVkKCkgZGVjaW1hbCBwbGFjZXMgb3V0IG9mIHJhbmdlOiB7ZHB9J1xuICAgICAgICAgKiAndG9GaXhlZCgpIHJvdW5kaW5nIG1vZGUgbm90IGFuIGludGVnZXI6IHtybX0nXG4gICAgICAgICAqICd0b0ZpeGVkKCkgcm91bmRpbmcgbW9kZSBvdXQgb2YgcmFuZ2U6IHtybX0nXG4gICAgICAgICAqL1xuICAgICAgICBQLnRvRml4ZWQgPSBmdW5jdGlvbiAoIGRwLCBybSApIHtcbiAgICAgICAgICAgIHJldHVybiBmb3JtYXQoIHRoaXMsIGRwICE9IG51bGwgJiYgaXNWYWxpZEludCggZHAsIDAsIE1BWCwgMjAgKVxuICAgICAgICAgICAgICA/IH5+ZHAgKyB0aGlzLmUgKyAxIDogbnVsbCwgcm0sIDIwICk7XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gYSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlciBpbiBmaXhlZC1wb2ludCBub3RhdGlvbiByb3VuZGVkXG4gICAgICAgICAqIHVzaW5nIHJtIG9yIFJPVU5ESU5HX01PREUgdG8gZHAgZGVjaW1hbCBwbGFjZXMsIGFuZCBmb3JtYXR0ZWQgYWNjb3JkaW5nIHRvIHRoZSBwcm9wZXJ0aWVzXG4gICAgICAgICAqIG9mIHRoZSBGT1JNQVQgb2JqZWN0IChzZWUgQmlnTnVtYmVyLmNvbmZpZykuXG4gICAgICAgICAqXG4gICAgICAgICAqIEZPUk1BVCA9IHtcbiAgICAgICAgICogICAgICBkZWNpbWFsU2VwYXJhdG9yIDogJy4nLFxuICAgICAgICAgKiAgICAgIGdyb3VwU2VwYXJhdG9yIDogJywnLFxuICAgICAgICAgKiAgICAgIGdyb3VwU2l6ZSA6IDMsXG4gICAgICAgICAqICAgICAgc2Vjb25kYXJ5R3JvdXBTaXplIDogMCxcbiAgICAgICAgICogICAgICBmcmFjdGlvbkdyb3VwU2VwYXJhdG9yIDogJ1xceEEwJywgICAgLy8gbm9uLWJyZWFraW5nIHNwYWNlXG4gICAgICAgICAqICAgICAgZnJhY3Rpb25Hcm91cFNpemUgOiAwXG4gICAgICAgICAqIH07XG4gICAgICAgICAqXG4gICAgICAgICAqIFtkcF0ge251bWJlcn0gRGVjaW1hbCBwbGFjZXMuIEludGVnZXIsIDAgdG8gTUFYIGluY2x1c2l2ZS5cbiAgICAgICAgICogW3JtXSB7bnVtYmVyfSBSb3VuZGluZyBtb2RlLiBJbnRlZ2VyLCAwIHRvIDggaW5jbHVzaXZlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAndG9Gb3JtYXQoKSBkZWNpbWFsIHBsYWNlcyBub3QgYW4gaW50ZWdlcjoge2RwfSdcbiAgICAgICAgICogJ3RvRm9ybWF0KCkgZGVjaW1hbCBwbGFjZXMgb3V0IG9mIHJhbmdlOiB7ZHB9J1xuICAgICAgICAgKiAndG9Gb3JtYXQoKSByb3VuZGluZyBtb2RlIG5vdCBhbiBpbnRlZ2VyOiB7cm19J1xuICAgICAgICAgKiAndG9Gb3JtYXQoKSByb3VuZGluZyBtb2RlIG91dCBvZiByYW5nZToge3JtfSdcbiAgICAgICAgICovXG4gICAgICAgIFAudG9Gb3JtYXQgPSBmdW5jdGlvbiAoIGRwLCBybSApIHtcbiAgICAgICAgICAgIHZhciBzdHIgPSBmb3JtYXQoIHRoaXMsIGRwICE9IG51bGwgJiYgaXNWYWxpZEludCggZHAsIDAsIE1BWCwgMjEgKVxuICAgICAgICAgICAgICA/IH5+ZHAgKyB0aGlzLmUgKyAxIDogbnVsbCwgcm0sIDIxICk7XG5cbiAgICAgICAgICAgIGlmICggdGhpcy5jICkge1xuICAgICAgICAgICAgICAgIHZhciBpLFxuICAgICAgICAgICAgICAgICAgICBhcnIgPSBzdHIuc3BsaXQoJy4nKSxcbiAgICAgICAgICAgICAgICAgICAgZzEgPSArRk9STUFULmdyb3VwU2l6ZSxcbiAgICAgICAgICAgICAgICAgICAgZzIgPSArRk9STUFULnNlY29uZGFyeUdyb3VwU2l6ZSxcbiAgICAgICAgICAgICAgICAgICAgZ3JvdXBTZXBhcmF0b3IgPSBGT1JNQVQuZ3JvdXBTZXBhcmF0b3IsXG4gICAgICAgICAgICAgICAgICAgIGludFBhcnQgPSBhcnJbMF0sXG4gICAgICAgICAgICAgICAgICAgIGZyYWN0aW9uUGFydCA9IGFyclsxXSxcbiAgICAgICAgICAgICAgICAgICAgaXNOZWcgPSB0aGlzLnMgPCAwLFxuICAgICAgICAgICAgICAgICAgICBpbnREaWdpdHMgPSBpc05lZyA/IGludFBhcnQuc2xpY2UoMSkgOiBpbnRQYXJ0LFxuICAgICAgICAgICAgICAgICAgICBsZW4gPSBpbnREaWdpdHMubGVuZ3RoO1xuXG4gICAgICAgICAgICAgICAgaWYgKGcyKSBpID0gZzEsIGcxID0gZzIsIGcyID0gaSwgbGVuIC09IGk7XG5cbiAgICAgICAgICAgICAgICBpZiAoIGcxID4gMCAmJiBsZW4gPiAwICkge1xuICAgICAgICAgICAgICAgICAgICBpID0gbGVuICUgZzEgfHwgZzE7XG4gICAgICAgICAgICAgICAgICAgIGludFBhcnQgPSBpbnREaWdpdHMuc3Vic3RyKCAwLCBpICk7XG5cbiAgICAgICAgICAgICAgICAgICAgZm9yICggOyBpIDwgbGVuOyBpICs9IGcxICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaW50UGFydCArPSBncm91cFNlcGFyYXRvciArIGludERpZ2l0cy5zdWJzdHIoIGksIGcxICk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBpZiAoIGcyID4gMCApIGludFBhcnQgKz0gZ3JvdXBTZXBhcmF0b3IgKyBpbnREaWdpdHMuc2xpY2UoaSk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChpc05lZykgaW50UGFydCA9ICctJyArIGludFBhcnQ7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgc3RyID0gZnJhY3Rpb25QYXJ0XG4gICAgICAgICAgICAgICAgICA/IGludFBhcnQgKyBGT1JNQVQuZGVjaW1hbFNlcGFyYXRvciArICggKCBnMiA9ICtGT1JNQVQuZnJhY3Rpb25Hcm91cFNpemUgKVxuICAgICAgICAgICAgICAgICAgICA/IGZyYWN0aW9uUGFydC5yZXBsYWNlKCBuZXcgUmVnRXhwKCAnXFxcXGR7JyArIGcyICsgJ31cXFxcQicsICdnJyApLFxuICAgICAgICAgICAgICAgICAgICAgICckJicgKyBGT1JNQVQuZnJhY3Rpb25Hcm91cFNlcGFyYXRvciApXG4gICAgICAgICAgICAgICAgICAgIDogZnJhY3Rpb25QYXJ0IClcbiAgICAgICAgICAgICAgICAgIDogaW50UGFydDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHN0cjtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiBhIHN0cmluZyBhcnJheSByZXByZXNlbnRpbmcgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIGFzIGEgc2ltcGxlIGZyYWN0aW9uIHdpdGhcbiAgICAgICAgICogYW4gaW50ZWdlciBudW1lcmF0b3IgYW5kIGFuIGludGVnZXIgZGVub21pbmF0b3IuIFRoZSBkZW5vbWluYXRvciB3aWxsIGJlIGEgcG9zaXRpdmVcbiAgICAgICAgICogbm9uLXplcm8gdmFsdWUgbGVzcyB0aGFuIG9yIGVxdWFsIHRvIHRoZSBzcGVjaWZpZWQgbWF4aW11bSBkZW5vbWluYXRvci4gSWYgYSBtYXhpbXVtXG4gICAgICAgICAqIGRlbm9taW5hdG9yIGlzIG5vdCBzcGVjaWZpZWQsIHRoZSBkZW5vbWluYXRvciB3aWxsIGJlIHRoZSBsb3dlc3QgdmFsdWUgbmVjZXNzYXJ5IHRvXG4gICAgICAgICAqIHJlcHJlc2VudCB0aGUgbnVtYmVyIGV4YWN0bHkuXG4gICAgICAgICAqXG4gICAgICAgICAqIFttZF0ge251bWJlcnxzdHJpbmd8QmlnTnVtYmVyfSBJbnRlZ2VyID49IDEgYW5kIDwgSW5maW5pdHkuIFRoZSBtYXhpbXVtIGRlbm9taW5hdG9yLlxuICAgICAgICAgKlxuICAgICAgICAgKiAndG9GcmFjdGlvbigpIG1heCBkZW5vbWluYXRvciBub3QgYW4gaW50ZWdlcjoge21kfSdcbiAgICAgICAgICogJ3RvRnJhY3Rpb24oKSBtYXggZGVub21pbmF0b3Igb3V0IG9mIHJhbmdlOiB7bWR9J1xuICAgICAgICAgKi9cbiAgICAgICAgUC50b0ZyYWN0aW9uID0gZnVuY3Rpb24gKG1kKSB7XG4gICAgICAgICAgICB2YXIgYXJyLCBkMCwgZDIsIGUsIGV4cCwgbiwgbjAsIHEsIHMsXG4gICAgICAgICAgICAgICAgayA9IEVSUk9SUyxcbiAgICAgICAgICAgICAgICB4ID0gdGhpcyxcbiAgICAgICAgICAgICAgICB4YyA9IHguYyxcbiAgICAgICAgICAgICAgICBkID0gbmV3IEJpZ051bWJlcihPTkUpLFxuICAgICAgICAgICAgICAgIG4xID0gZDAgPSBuZXcgQmlnTnVtYmVyKE9ORSksXG4gICAgICAgICAgICAgICAgZDEgPSBuMCA9IG5ldyBCaWdOdW1iZXIoT05FKTtcblxuICAgICAgICAgICAgaWYgKCBtZCAhPSBudWxsICkge1xuICAgICAgICAgICAgICAgIEVSUk9SUyA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIG4gPSBuZXcgQmlnTnVtYmVyKG1kKTtcbiAgICAgICAgICAgICAgICBFUlJPUlMgPSBrO1xuXG4gICAgICAgICAgICAgICAgaWYgKCAhKCBrID0gbi5pc0ludCgpICkgfHwgbi5sdChPTkUpICkge1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChFUlJPUlMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJhaXNlKCAyMixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgJ21heCBkZW5vbWluYXRvciAnICsgKCBrID8gJ291dCBvZiByYW5nZScgOiAnbm90IGFuIGludGVnZXInICksIG1kICk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAvLyBFUlJPUlMgaXMgZmFsc2U6XG4gICAgICAgICAgICAgICAgICAgIC8vIElmIG1kIGlzIGEgZmluaXRlIG5vbi1pbnRlZ2VyID49IDEsIHJvdW5kIGl0IHRvIGFuIGludGVnZXIgYW5kIHVzZSBpdC5cbiAgICAgICAgICAgICAgICAgICAgbWQgPSAhayAmJiBuLmMgJiYgcm91bmQoIG4sIG4uZSArIDEsIDEgKS5ndGUoT05FKSA/IG4gOiBudWxsO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCAheGMgKSByZXR1cm4geC50b1N0cmluZygpO1xuICAgICAgICAgICAgcyA9IGNvZWZmVG9TdHJpbmcoeGMpO1xuXG4gICAgICAgICAgICAvLyBEZXRlcm1pbmUgaW5pdGlhbCBkZW5vbWluYXRvci5cbiAgICAgICAgICAgIC8vIGQgaXMgYSBwb3dlciBvZiAxMCBhbmQgdGhlIG1pbmltdW0gbWF4IGRlbm9taW5hdG9yIHRoYXQgc3BlY2lmaWVzIHRoZSB2YWx1ZSBleGFjdGx5LlxuICAgICAgICAgICAgZSA9IGQuZSA9IHMubGVuZ3RoIC0geC5lIC0gMTtcbiAgICAgICAgICAgIGQuY1swXSA9IFBPV1NfVEVOWyAoIGV4cCA9IGUgJSBMT0dfQkFTRSApIDwgMCA/IExPR19CQVNFICsgZXhwIDogZXhwIF07XG4gICAgICAgICAgICBtZCA9ICFtZCB8fCBuLmNtcChkKSA+IDAgPyAoIGUgPiAwID8gZCA6IG4xICkgOiBuO1xuXG4gICAgICAgICAgICBleHAgPSBNQVhfRVhQO1xuICAgICAgICAgICAgTUFYX0VYUCA9IDEgLyAwO1xuICAgICAgICAgICAgbiA9IG5ldyBCaWdOdW1iZXIocyk7XG5cbiAgICAgICAgICAgIC8vIG4wID0gZDEgPSAwXG4gICAgICAgICAgICBuMC5jWzBdID0gMDtcblxuICAgICAgICAgICAgZm9yICggOyA7ICkgIHtcbiAgICAgICAgICAgICAgICBxID0gZGl2KCBuLCBkLCAwLCAxICk7XG4gICAgICAgICAgICAgICAgZDIgPSBkMC5wbHVzKCBxLnRpbWVzKGQxKSApO1xuICAgICAgICAgICAgICAgIGlmICggZDIuY21wKG1kKSA9PSAxICkgYnJlYWs7XG4gICAgICAgICAgICAgICAgZDAgPSBkMTtcbiAgICAgICAgICAgICAgICBkMSA9IGQyO1xuICAgICAgICAgICAgICAgIG4xID0gbjAucGx1cyggcS50aW1lcyggZDIgPSBuMSApICk7XG4gICAgICAgICAgICAgICAgbjAgPSBkMjtcbiAgICAgICAgICAgICAgICBkID0gbi5taW51cyggcS50aW1lcyggZDIgPSBkICkgKTtcbiAgICAgICAgICAgICAgICBuID0gZDI7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGQyID0gZGl2KCBtZC5taW51cyhkMCksIGQxLCAwLCAxICk7XG4gICAgICAgICAgICBuMCA9IG4wLnBsdXMoIGQyLnRpbWVzKG4xKSApO1xuICAgICAgICAgICAgZDAgPSBkMC5wbHVzKCBkMi50aW1lcyhkMSkgKTtcbiAgICAgICAgICAgIG4wLnMgPSBuMS5zID0geC5zO1xuICAgICAgICAgICAgZSAqPSAyO1xuXG4gICAgICAgICAgICAvLyBEZXRlcm1pbmUgd2hpY2ggZnJhY3Rpb24gaXMgY2xvc2VyIHRvIHgsIG4wL2QwIG9yIG4xL2QxXG4gICAgICAgICAgICBhcnIgPSBkaXYoIG4xLCBkMSwgZSwgUk9VTkRJTkdfTU9ERSApLm1pbnVzKHgpLmFicygpLmNtcChcbiAgICAgICAgICAgICAgICAgIGRpdiggbjAsIGQwLCBlLCBST1VORElOR19NT0RFICkubWludXMoeCkuYWJzKCkgKSA8IDFcbiAgICAgICAgICAgICAgICAgICAgPyBbIG4xLnRvU3RyaW5nKCksIGQxLnRvU3RyaW5nKCkgXVxuICAgICAgICAgICAgICAgICAgICA6IFsgbjAudG9TdHJpbmcoKSwgZDAudG9TdHJpbmcoKSBdO1xuXG4gICAgICAgICAgICBNQVhfRVhQID0gZXhwO1xuICAgICAgICAgICAgcmV0dXJuIGFycjtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgY29udmVydGVkIHRvIGEgbnVtYmVyIHByaW1pdGl2ZS5cbiAgICAgICAgICovXG4gICAgICAgIFAudG9OdW1iZXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgeCA9IHRoaXM7XG5cbiAgICAgICAgICAgIC8vIEVuc3VyZSB6ZXJvIGhhcyBjb3JyZWN0IHNpZ24uXG4gICAgICAgICAgICByZXR1cm4gK3ggfHwgKCB4LnMgPyB4LnMgKiAwIDogTmFOICk7XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gYSBCaWdOdW1iZXIgd2hvc2UgdmFsdWUgaXMgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIHJhaXNlZCB0byB0aGUgcG93ZXIgbi5cbiAgICAgICAgICogSWYgbiBpcyBuZWdhdGl2ZSByb3VuZCBhY2NvcmRpbmcgdG8gREVDSU1BTF9QTEFDRVMgYW5kIFJPVU5ESU5HX01PREUuXG4gICAgICAgICAqIElmIFBPV19QUkVDSVNJT04gaXMgbm90IDAsIHJvdW5kIHRvIFBPV19QUkVDSVNJT04gdXNpbmcgUk9VTkRJTkdfTU9ERS5cbiAgICAgICAgICpcbiAgICAgICAgICogbiB7bnVtYmVyfSBJbnRlZ2VyLCAtOTAwNzE5OTI1NDc0MDk5MiB0byA5MDA3MTk5MjU0NzQwOTkyIGluY2x1c2l2ZS5cbiAgICAgICAgICogKFBlcmZvcm1zIDU0IGxvb3AgaXRlcmF0aW9ucyBmb3IgbiBvZiA5MDA3MTk5MjU0NzQwOTkyLilcbiAgICAgICAgICpcbiAgICAgICAgICogJ3BvdygpIGV4cG9uZW50IG5vdCBhbiBpbnRlZ2VyOiB7bn0nXG4gICAgICAgICAqICdwb3coKSBleHBvbmVudCBvdXQgb2YgcmFuZ2U6IHtufSdcbiAgICAgICAgICovXG4gICAgICAgIFAudG9Qb3dlciA9IFAucG93ID0gZnVuY3Rpb24gKG4pIHtcbiAgICAgICAgICAgIHZhciBrLCB5LFxuICAgICAgICAgICAgICAgIGkgPSBtYXRoZmxvb3IoIG4gPCAwID8gLW4gOiArbiApLFxuICAgICAgICAgICAgICAgIHggPSB0aGlzO1xuXG4gICAgICAgICAgICAvLyBQYXNzIMKxSW5maW5pdHkgdG8gTWF0aC5wb3cgaWYgZXhwb25lbnQgaXMgb3V0IG9mIHJhbmdlLlxuICAgICAgICAgICAgaWYgKCAhaXNWYWxpZEludCggbiwgLU1BWF9TQUZFX0lOVEVHRVIsIE1BWF9TQUZFX0lOVEVHRVIsIDIzLCAnZXhwb25lbnQnICkgJiZcbiAgICAgICAgICAgICAgKCAhaXNGaW5pdGUobikgfHwgaSA+IE1BWF9TQUZFX0lOVEVHRVIgJiYgKCBuIC89IDAgKSB8fFxuICAgICAgICAgICAgICAgIHBhcnNlRmxvYXQobikgIT0gbiAmJiAhKCBuID0gTmFOICkgKSApIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbmV3IEJpZ051bWJlciggTWF0aC5wb3coICt4LCBuICkgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gVHJ1bmNhdGluZyBlYWNoIGNvZWZmaWNpZW50IGFycmF5IHRvIGEgbGVuZ3RoIG9mIGsgYWZ0ZXIgZWFjaCBtdWx0aXBsaWNhdGlvbiBlcXVhdGVzXG4gICAgICAgICAgICAvLyB0byB0cnVuY2F0aW5nIHNpZ25pZmljYW50IGRpZ2l0cyB0byBQT1dfUFJFQ0lTSU9OICsgWzI4LCA0MV0sIGkuZS4gdGhlcmUgd2lsbCBiZSBhXG4gICAgICAgICAgICAvLyBtaW5pbXVtIG9mIDI4IGd1YXJkIGRpZ2l0cyByZXRhaW5lZC4gKFVzaW5nICsgMS41IHdvdWxkIGdpdmUgWzksIDIxXSBndWFyZCBkaWdpdHMuKVxuICAgICAgICAgICAgayA9IFBPV19QUkVDSVNJT04gPyBtYXRoY2VpbCggUE9XX1BSRUNJU0lPTiAvIExPR19CQVNFICsgMiApIDogMDtcbiAgICAgICAgICAgIHkgPSBuZXcgQmlnTnVtYmVyKE9ORSk7XG5cbiAgICAgICAgICAgIGZvciAoIDsgOyApIHtcblxuICAgICAgICAgICAgICAgIGlmICggaSAlIDIgKSB7XG4gICAgICAgICAgICAgICAgICAgIHkgPSB5LnRpbWVzKHgpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoICF5LmMgKSBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgaWYgKCBrICYmIHkuYy5sZW5ndGggPiBrICkgeS5jLmxlbmd0aCA9IGs7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaSA9IG1hdGhmbG9vciggaSAvIDIgKTtcbiAgICAgICAgICAgICAgICBpZiAoICFpICkgYnJlYWs7XG5cbiAgICAgICAgICAgICAgICB4ID0geC50aW1lcyh4KTtcbiAgICAgICAgICAgICAgICBpZiAoIGsgJiYgeC5jICYmIHguYy5sZW5ndGggPiBrICkgeC5jLmxlbmd0aCA9IGs7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICggbiA8IDAgKSB5ID0gT05FLmRpdih5KTtcbiAgICAgICAgICAgIHJldHVybiBrID8gcm91bmQoIHksIFBPV19QUkVDSVNJT04sIFJPVU5ESU5HX01PREUgKSA6IHk7XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gYSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlciByb3VuZGVkIHRvIHNkIHNpZ25pZmljYW50IGRpZ2l0c1xuICAgICAgICAgKiB1c2luZyByb3VuZGluZyBtb2RlIHJtIG9yIFJPVU5ESU5HX01PREUuIElmIHNkIGlzIGxlc3MgdGhhbiB0aGUgbnVtYmVyIG9mIGRpZ2l0c1xuICAgICAgICAgKiBuZWNlc3NhcnkgdG8gcmVwcmVzZW50IHRoZSBpbnRlZ2VyIHBhcnQgb2YgdGhlIHZhbHVlIGluIGZpeGVkLXBvaW50IG5vdGF0aW9uLCB0aGVuIHVzZVxuICAgICAgICAgKiBleHBvbmVudGlhbCBub3RhdGlvbi5cbiAgICAgICAgICpcbiAgICAgICAgICogW3NkXSB7bnVtYmVyfSBTaWduaWZpY2FudCBkaWdpdHMuIEludGVnZXIsIDEgdG8gTUFYIGluY2x1c2l2ZS5cbiAgICAgICAgICogW3JtXSB7bnVtYmVyfSBSb3VuZGluZyBtb2RlLiBJbnRlZ2VyLCAwIHRvIDggaW5jbHVzaXZlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAndG9QcmVjaXNpb24oKSBwcmVjaXNpb24gbm90IGFuIGludGVnZXI6IHtzZH0nXG4gICAgICAgICAqICd0b1ByZWNpc2lvbigpIHByZWNpc2lvbiBvdXQgb2YgcmFuZ2U6IHtzZH0nXG4gICAgICAgICAqICd0b1ByZWNpc2lvbigpIHJvdW5kaW5nIG1vZGUgbm90IGFuIGludGVnZXI6IHtybX0nXG4gICAgICAgICAqICd0b1ByZWNpc2lvbigpIHJvdW5kaW5nIG1vZGUgb3V0IG9mIHJhbmdlOiB7cm19J1xuICAgICAgICAgKi9cbiAgICAgICAgUC50b1ByZWNpc2lvbiA9IGZ1bmN0aW9uICggc2QsIHJtICkge1xuICAgICAgICAgICAgcmV0dXJuIGZvcm1hdCggdGhpcywgc2QgIT0gbnVsbCAmJiBpc1ZhbGlkSW50KCBzZCwgMSwgTUFYLCAyNCwgJ3ByZWNpc2lvbicgKVxuICAgICAgICAgICAgICA/IHNkIHwgMCA6IG51bGwsIHJtLCAyNCApO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIGEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgaW4gYmFzZSBiLCBvciBiYXNlIDEwIGlmIGIgaXNcbiAgICAgICAgICogb21pdHRlZC4gSWYgYSBiYXNlIGlzIHNwZWNpZmllZCwgaW5jbHVkaW5nIGJhc2UgMTAsIHJvdW5kIGFjY29yZGluZyB0byBERUNJTUFMX1BMQUNFUyBhbmRcbiAgICAgICAgICogUk9VTkRJTkdfTU9ERS4gSWYgYSBiYXNlIGlzIG5vdCBzcGVjaWZpZWQsIGFuZCB0aGlzIEJpZ051bWJlciBoYXMgYSBwb3NpdGl2ZSBleHBvbmVudFxuICAgICAgICAgKiB0aGF0IGlzIGVxdWFsIHRvIG9yIGdyZWF0ZXIgdGhhbiBUT19FWFBfUE9TLCBvciBhIG5lZ2F0aXZlIGV4cG9uZW50IGVxdWFsIHRvIG9yIGxlc3MgdGhhblxuICAgICAgICAgKiBUT19FWFBfTkVHLCByZXR1cm4gZXhwb25lbnRpYWwgbm90YXRpb24uXG4gICAgICAgICAqXG4gICAgICAgICAqIFtiXSB7bnVtYmVyfSBJbnRlZ2VyLCAyIHRvIDY0IGluY2x1c2l2ZS5cbiAgICAgICAgICpcbiAgICAgICAgICogJ3RvU3RyaW5nKCkgYmFzZSBub3QgYW4gaW50ZWdlcjoge2J9J1xuICAgICAgICAgKiAndG9TdHJpbmcoKSBiYXNlIG91dCBvZiByYW5nZToge2J9J1xuICAgICAgICAgKi9cbiAgICAgICAgUC50b1N0cmluZyA9IGZ1bmN0aW9uIChiKSB7XG4gICAgICAgICAgICB2YXIgc3RyLFxuICAgICAgICAgICAgICAgIG4gPSB0aGlzLFxuICAgICAgICAgICAgICAgIHMgPSBuLnMsXG4gICAgICAgICAgICAgICAgZSA9IG4uZTtcblxuICAgICAgICAgICAgLy8gSW5maW5pdHkgb3IgTmFOP1xuICAgICAgICAgICAgaWYgKCBlID09PSBudWxsICkge1xuXG4gICAgICAgICAgICAgICAgaWYgKHMpIHtcbiAgICAgICAgICAgICAgICAgICAgc3RyID0gJ0luZmluaXR5JztcbiAgICAgICAgICAgICAgICAgICAgaWYgKCBzIDwgMCApIHN0ciA9ICctJyArIHN0cjtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBzdHIgPSAnTmFOJztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHN0ciA9IGNvZWZmVG9TdHJpbmcoIG4uYyApO1xuXG4gICAgICAgICAgICAgICAgaWYgKCBiID09IG51bGwgfHwgIWlzVmFsaWRJbnQoIGIsIDIsIDY0LCAyNSwgJ2Jhc2UnICkgKSB7XG4gICAgICAgICAgICAgICAgICAgIHN0ciA9IGUgPD0gVE9fRVhQX05FRyB8fCBlID49IFRPX0VYUF9QT1NcbiAgICAgICAgICAgICAgICAgICAgICA/IHRvRXhwb25lbnRpYWwoIHN0ciwgZSApXG4gICAgICAgICAgICAgICAgICAgICAgOiB0b0ZpeGVkUG9pbnQoIHN0ciwgZSApO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHN0ciA9IGNvbnZlcnRCYXNlKCB0b0ZpeGVkUG9pbnQoIHN0ciwgZSApLCBiIHwgMCwgMTAsIHMgKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoIHMgPCAwICYmIG4uY1swXSApIHN0ciA9ICctJyArIHN0cjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHN0cjtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiBhIG5ldyBCaWdOdW1iZXIgd2hvc2UgdmFsdWUgaXMgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIHRydW5jYXRlZCB0byBhIHdob2xlXG4gICAgICAgICAqIG51bWJlci5cbiAgICAgICAgICovXG4gICAgICAgIFAudHJ1bmNhdGVkID0gUC50cnVuYyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiByb3VuZCggbmV3IEJpZ051bWJlcih0aGlzKSwgdGhpcy5lICsgMSwgMSApO1xuICAgICAgICB9O1xuXG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gYXMgdG9TdHJpbmcsIGJ1dCBkbyBub3QgYWNjZXB0IGEgYmFzZSBhcmd1bWVudC5cbiAgICAgICAgICovXG4gICAgICAgIFAudmFsdWVPZiA9IFAudG9KU09OID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudG9TdHJpbmcoKTtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8vIEFsaWFzZXMgZm9yIEJpZ0RlY2ltYWwgbWV0aG9kcy5cbiAgICAgICAgLy9QLmFkZCA9IFAucGx1czsgICAgICAgICAvLyBQLmFkZCBpbmNsdWRlZCBhYm92ZVxuICAgICAgICAvL1Auc3VidHJhY3QgPSBQLm1pbnVzOyAgIC8vIFAuc3ViIGluY2x1ZGVkIGFib3ZlXG4gICAgICAgIC8vUC5tdWx0aXBseSA9IFAudGltZXM7ICAgLy8gUC5tdWwgaW5jbHVkZWQgYWJvdmVcbiAgICAgICAgLy9QLmRpdmlkZSA9IFAuZGl2O1xuICAgICAgICAvL1AucmVtYWluZGVyID0gUC5tb2Q7XG4gICAgICAgIC8vUC5jb21wYXJlVG8gPSBQLmNtcDtcbiAgICAgICAgLy9QLm5lZ2F0ZSA9IFAubmVnO1xuXG5cbiAgICAgICAgaWYgKCBjb25maWdPYmogIT0gbnVsbCApIEJpZ051bWJlci5jb25maWcoY29uZmlnT2JqKTtcblxuICAgICAgICByZXR1cm4gQmlnTnVtYmVyO1xuICAgIH1cblxuXG4gICAgLy8gUFJJVkFURSBIRUxQRVIgRlVOQ1RJT05TXG5cblxuICAgIGZ1bmN0aW9uIGJpdEZsb29yKG4pIHtcbiAgICAgICAgdmFyIGkgPSBuIHwgMDtcbiAgICAgICAgcmV0dXJuIG4gPiAwIHx8IG4gPT09IGkgPyBpIDogaSAtIDE7XG4gICAgfVxuXG5cbiAgICAvLyBSZXR1cm4gYSBjb2VmZmljaWVudCBhcnJheSBhcyBhIHN0cmluZyBvZiBiYXNlIDEwIGRpZ2l0cy5cbiAgICBmdW5jdGlvbiBjb2VmZlRvU3RyaW5nKGEpIHtcbiAgICAgICAgdmFyIHMsIHosXG4gICAgICAgICAgICBpID0gMSxcbiAgICAgICAgICAgIGogPSBhLmxlbmd0aCxcbiAgICAgICAgICAgIHIgPSBhWzBdICsgJyc7XG5cbiAgICAgICAgZm9yICggOyBpIDwgajsgKSB7XG4gICAgICAgICAgICBzID0gYVtpKytdICsgJyc7XG4gICAgICAgICAgICB6ID0gTE9HX0JBU0UgLSBzLmxlbmd0aDtcbiAgICAgICAgICAgIGZvciAoIDsgei0tOyBzID0gJzAnICsgcyApO1xuICAgICAgICAgICAgciArPSBzO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRGV0ZXJtaW5lIHRyYWlsaW5nIHplcm9zLlxuICAgICAgICBmb3IgKCBqID0gci5sZW5ndGg7IHIuY2hhckNvZGVBdCgtLWopID09PSA0ODsgKTtcbiAgICAgICAgcmV0dXJuIHIuc2xpY2UoIDAsIGogKyAxIHx8IDEgKTtcbiAgICB9XG5cblxuICAgIC8vIENvbXBhcmUgdGhlIHZhbHVlIG9mIEJpZ051bWJlcnMgeCBhbmQgeS5cbiAgICBmdW5jdGlvbiBjb21wYXJlKCB4LCB5ICkge1xuICAgICAgICB2YXIgYSwgYixcbiAgICAgICAgICAgIHhjID0geC5jLFxuICAgICAgICAgICAgeWMgPSB5LmMsXG4gICAgICAgICAgICBpID0geC5zLFxuICAgICAgICAgICAgaiA9IHkucyxcbiAgICAgICAgICAgIGsgPSB4LmUsXG4gICAgICAgICAgICBsID0geS5lO1xuXG4gICAgICAgIC8vIEVpdGhlciBOYU4/XG4gICAgICAgIGlmICggIWkgfHwgIWogKSByZXR1cm4gbnVsbDtcblxuICAgICAgICBhID0geGMgJiYgIXhjWzBdO1xuICAgICAgICBiID0geWMgJiYgIXljWzBdO1xuXG4gICAgICAgIC8vIEVpdGhlciB6ZXJvP1xuICAgICAgICBpZiAoIGEgfHwgYiApIHJldHVybiBhID8gYiA/IDAgOiAtaiA6IGk7XG5cbiAgICAgICAgLy8gU2lnbnMgZGlmZmVyP1xuICAgICAgICBpZiAoIGkgIT0gaiApIHJldHVybiBpO1xuXG4gICAgICAgIGEgPSBpIDwgMDtcbiAgICAgICAgYiA9IGsgPT0gbDtcblxuICAgICAgICAvLyBFaXRoZXIgSW5maW5pdHk/XG4gICAgICAgIGlmICggIXhjIHx8ICF5YyApIHJldHVybiBiID8gMCA6ICF4YyBeIGEgPyAxIDogLTE7XG5cbiAgICAgICAgLy8gQ29tcGFyZSBleHBvbmVudHMuXG4gICAgICAgIGlmICggIWIgKSByZXR1cm4gayA+IGwgXiBhID8gMSA6IC0xO1xuXG4gICAgICAgIGogPSAoIGsgPSB4Yy5sZW5ndGggKSA8ICggbCA9IHljLmxlbmd0aCApID8gayA6IGw7XG5cbiAgICAgICAgLy8gQ29tcGFyZSBkaWdpdCBieSBkaWdpdC5cbiAgICAgICAgZm9yICggaSA9IDA7IGkgPCBqOyBpKysgKSBpZiAoIHhjW2ldICE9IHljW2ldICkgcmV0dXJuIHhjW2ldID4geWNbaV0gXiBhID8gMSA6IC0xO1xuXG4gICAgICAgIC8vIENvbXBhcmUgbGVuZ3Rocy5cbiAgICAgICAgcmV0dXJuIGsgPT0gbCA/IDAgOiBrID4gbCBeIGEgPyAxIDogLTE7XG4gICAgfVxuXG5cbiAgICAvKlxuICAgICAqIFJldHVybiB0cnVlIGlmIG4gaXMgYSB2YWxpZCBudW1iZXIgaW4gcmFuZ2UsIG90aGVyd2lzZSBmYWxzZS5cbiAgICAgKiBVc2UgZm9yIGFyZ3VtZW50IHZhbGlkYXRpb24gd2hlbiBFUlJPUlMgaXMgZmFsc2UuXG4gICAgICogTm90ZTogcGFyc2VJbnQoJzFlKzEnKSA9PSAxIGJ1dCBwYXJzZUZsb2F0KCcxZSsxJykgPT0gMTAuXG4gICAgICovXG4gICAgZnVuY3Rpb24gaW50VmFsaWRhdG9yTm9FcnJvcnMoIG4sIG1pbiwgbWF4ICkge1xuICAgICAgICByZXR1cm4gKCBuID0gdHJ1bmNhdGUobikgKSA+PSBtaW4gJiYgbiA8PSBtYXg7XG4gICAgfVxuXG5cbiAgICBmdW5jdGlvbiBpc0FycmF5KG9iaikge1xuICAgICAgICByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG9iaikgPT0gJ1tvYmplY3QgQXJyYXldJztcbiAgICB9XG5cblxuICAgIC8qXG4gICAgICogQ29udmVydCBzdHJpbmcgb2YgYmFzZUluIHRvIGFuIGFycmF5IG9mIG51bWJlcnMgb2YgYmFzZU91dC5cbiAgICAgKiBFZy4gY29udmVydEJhc2UoJzI1NScsIDEwLCAxNikgcmV0dXJucyBbMTUsIDE1XS5cbiAgICAgKiBFZy4gY29udmVydEJhc2UoJ2ZmJywgMTYsIDEwKSByZXR1cm5zIFsyLCA1LCA1XS5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiB0b0Jhc2VPdXQoIHN0ciwgYmFzZUluLCBiYXNlT3V0ICkge1xuICAgICAgICB2YXIgaixcbiAgICAgICAgICAgIGFyciA9IFswXSxcbiAgICAgICAgICAgIGFyckwsXG4gICAgICAgICAgICBpID0gMCxcbiAgICAgICAgICAgIGxlbiA9IHN0ci5sZW5ndGg7XG5cbiAgICAgICAgZm9yICggOyBpIDwgbGVuOyApIHtcbiAgICAgICAgICAgIGZvciAoIGFyckwgPSBhcnIubGVuZ3RoOyBhcnJMLS07IGFyclthcnJMXSAqPSBiYXNlSW4gKTtcbiAgICAgICAgICAgIGFyclsgaiA9IDAgXSArPSBBTFBIQUJFVC5pbmRleE9mKCBzdHIuY2hhckF0KCBpKysgKSApO1xuXG4gICAgICAgICAgICBmb3IgKCA7IGogPCBhcnIubGVuZ3RoOyBqKysgKSB7XG5cbiAgICAgICAgICAgICAgICBpZiAoIGFycltqXSA+IGJhc2VPdXQgLSAxICkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIGFycltqICsgMV0gPT0gbnVsbCApIGFycltqICsgMV0gPSAwO1xuICAgICAgICAgICAgICAgICAgICBhcnJbaiArIDFdICs9IGFycltqXSAvIGJhc2VPdXQgfCAwO1xuICAgICAgICAgICAgICAgICAgICBhcnJbal0gJT0gYmFzZU91dDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYXJyLnJldmVyc2UoKTtcbiAgICB9XG5cblxuICAgIGZ1bmN0aW9uIHRvRXhwb25lbnRpYWwoIHN0ciwgZSApIHtcbiAgICAgICAgcmV0dXJuICggc3RyLmxlbmd0aCA+IDEgPyBzdHIuY2hhckF0KDApICsgJy4nICsgc3RyLnNsaWNlKDEpIDogc3RyICkgK1xuICAgICAgICAgICggZSA8IDAgPyAnZScgOiAnZSsnICkgKyBlO1xuICAgIH1cblxuXG4gICAgZnVuY3Rpb24gdG9GaXhlZFBvaW50KCBzdHIsIGUgKSB7XG4gICAgICAgIHZhciBsZW4sIHo7XG5cbiAgICAgICAgLy8gTmVnYXRpdmUgZXhwb25lbnQ/XG4gICAgICAgIGlmICggZSA8IDAgKSB7XG5cbiAgICAgICAgICAgIC8vIFByZXBlbmQgemVyb3MuXG4gICAgICAgICAgICBmb3IgKCB6ID0gJzAuJzsgKytlOyB6ICs9ICcwJyApO1xuICAgICAgICAgICAgc3RyID0geiArIHN0cjtcblxuICAgICAgICAvLyBQb3NpdGl2ZSBleHBvbmVudFxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgbGVuID0gc3RyLmxlbmd0aDtcblxuICAgICAgICAgICAgLy8gQXBwZW5kIHplcm9zLlxuICAgICAgICAgICAgaWYgKCArK2UgPiBsZW4gKSB7XG4gICAgICAgICAgICAgICAgZm9yICggeiA9ICcwJywgZSAtPSBsZW47IC0tZTsgeiArPSAnMCcgKTtcbiAgICAgICAgICAgICAgICBzdHIgKz0gejtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoIGUgPCBsZW4gKSB7XG4gICAgICAgICAgICAgICAgc3RyID0gc3RyLnNsaWNlKCAwLCBlICkgKyAnLicgKyBzdHIuc2xpY2UoZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gc3RyO1xuICAgIH1cblxuXG4gICAgZnVuY3Rpb24gdHJ1bmNhdGUobikge1xuICAgICAgICBuID0gcGFyc2VGbG9hdChuKTtcbiAgICAgICAgcmV0dXJuIG4gPCAwID8gbWF0aGNlaWwobikgOiBtYXRoZmxvb3Iobik7XG4gICAgfVxuXG5cbiAgICAvLyBFWFBPUlRcblxuXG4gICAgQmlnTnVtYmVyID0gYW5vdGhlcigpO1xuXG4gICAgLy8gQU1ELlxuICAgIGlmICggdHlwZW9mIGRlZmluZSA9PSAnZnVuY3Rpb24nICYmIGRlZmluZS5hbWQgKSB7XG4gICAgICAgIGRlZmluZSggZnVuY3Rpb24gKCkgeyByZXR1cm4gQmlnTnVtYmVyOyB9ICk7XG5cbiAgICAvLyBOb2RlIGFuZCBvdGhlciBlbnZpcm9ubWVudHMgdGhhdCBzdXBwb3J0IG1vZHVsZS5leHBvcnRzLlxuICAgIH0gZWxzZSBpZiAoIHR5cGVvZiBtb2R1bGUgIT0gJ3VuZGVmaW5lZCcgJiYgbW9kdWxlLmV4cG9ydHMgKSB7XG4gICAgICAgIG1vZHVsZS5leHBvcnRzID0gQmlnTnVtYmVyO1xuICAgICAgICBpZiAoICFjcnlwdG8gKSB0cnkgeyBjcnlwdG8gPSByZXF1aXJlKCdjcnlwdG8nKTsgfSBjYXRjaCAoZSkge31cblxuICAgIC8vIEJyb3dzZXIuXG4gICAgfSBlbHNlIHtcbiAgICAgICAgZ2xvYmFsLkJpZ051bWJlciA9IEJpZ051bWJlcjtcbiAgICB9XG59KSh0aGlzKTtcbiIsInZhciB3ZWIzID0gcmVxdWlyZSgnLi9saWIvd2ViMycpO1xud2ViMy5wcm92aWRlcnMuSHR0cFByb3ZpZGVyID0gcmVxdWlyZSgnLi9saWIvd2ViMy9odHRwcHJvdmlkZXInKTtcbndlYjMucHJvdmlkZXJzLlF0U3luY1Byb3ZpZGVyID0gcmVxdWlyZSgnLi9saWIvd2ViMy9xdHN5bmMnKTtcbndlYjMuZXRoLmNvbnRyYWN0ID0gcmVxdWlyZSgnLi9saWIvd2ViMy9jb250cmFjdCcpO1xud2ViMy5ldGgubmFtZXJlZyA9IHJlcXVpcmUoJy4vbGliL3dlYjMvbmFtZXJlZycpO1xud2ViMy5ldGguc2VuZElCQU5UcmFuc2FjdGlvbiA9IHJlcXVpcmUoJy4vbGliL3dlYjMvdHJhbnNmZXInKTtcblxuLy8gZG9udCBvdmVycmlkZSBnbG9iYWwgdmFyaWFibGVcbmlmICh0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyAmJiB0eXBlb2Ygd2luZG93LndlYjMgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgd2luZG93LndlYjMgPSB3ZWIzO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHdlYjM7XG5cbiJdfQ== +//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJsaWIvc29saWRpdHkvY29kZXIuanMiLCJsaWIvc29saWRpdHkvZm9ybWF0dGVycy5qcyIsImxpYi9zb2xpZGl0eS9wYXJhbS5qcyIsImxpYi91dGlscy9icm93c2VyLXhoci5qcyIsImxpYi91dGlscy9jb25maWcuanMiLCJsaWIvdXRpbHMvc2hhMy5qcyIsImxpYi91dGlscy91dGlscy5qcyIsImxpYi92ZXJzaW9uLmpzb24iLCJsaWIvd2ViMy5qcyIsImxpYi93ZWIzL2JhdGNoLmpzIiwibGliL3dlYjMvY29udHJhY3QuanMiLCJsaWIvd2ViMy9kYi5qcyIsImxpYi93ZWIzL2Vycm9ycy5qcyIsImxpYi93ZWIzL2V0aC5qcyIsImxpYi93ZWIzL2V2ZW50LmpzIiwibGliL3dlYjMvZmlsdGVyLmpzIiwibGliL3dlYjMvZm9ybWF0dGVycy5qcyIsImxpYi93ZWIzL2Z1bmN0aW9uLmpzIiwibGliL3dlYjMvaHR0cHByb3ZpZGVyLmpzIiwibGliL3dlYjMvaWNhcC5qcyIsImxpYi93ZWIzL2pzb25ycGMuanMiLCJsaWIvd2ViMy9tZXRob2QuanMiLCJsaWIvd2ViMy9uYW1lcmVnLmpzIiwibGliL3dlYjMvbmV0LmpzIiwibGliL3dlYjMvcHJvcGVydHkuanMiLCJsaWIvd2ViMy9xdHN5bmMuanMiLCJsaWIvd2ViMy9yZXF1ZXN0bWFuYWdlci5qcyIsImxpYi93ZWIzL3NoaC5qcyIsImxpYi93ZWIzL3RyYW5zZmVyLmpzIiwibGliL3dlYjMvd2F0Y2hlcy5qcyIsIm5vZGVfbW9kdWxlcy9icm93c2VyaWZ5L2xpYi9fZW1wdHkuanMiLCJub2RlX21vZHVsZXMvY3J5cHRvLWpzL2NvcmUuanMiLCJub2RlX21vZHVsZXMvY3J5cHRvLWpzL3NoYTMuanMiLCJub2RlX21vZHVsZXMvY3J5cHRvLWpzL3g2NC1jb3JlLmpzIiwiYmlnbnVtYmVyLmpzIiwiaW5kZXguanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsZkE7QUFDQTtBQUNBO0FBQ0E7O0FDSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcExBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDblJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25NQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDak9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1S0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RQQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xIQTs7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNydUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbFVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9TQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNuRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqIFxuICogQGZpbGUgY29kZXIuanNcbiAqIEBhdXRob3IgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE1XG4gKi9cblxudmFyIEJpZ051bWJlciA9IHJlcXVpcmUoJ2JpZ251bWJlci5qcycpO1xudmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMvdXRpbHMnKTtcbnZhciBmID0gcmVxdWlyZSgnLi9mb3JtYXR0ZXJzJyk7XG52YXIgU29saWRpdHlQYXJhbSA9IHJlcXVpcmUoJy4vcGFyYW0nKTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBjaGVjayBpZiBhIHR5cGUgaXMgYW4gYXJyYXkgdHlwZVxuICpcbiAqIEBtZXRob2QgaXNBcnJheVR5cGVcbiAqIEBwYXJhbSB7U3RyaW5nfSB0eXBlXG4gKiBAcmV0dXJuIHtCb29sfSB0cnVlIGlzIHRoZSB0eXBlIGlzIGFuIGFycmF5LCBvdGhlcndpc2UgZmFsc2VcbiAqL1xudmFyIGlzQXJyYXlUeXBlID0gZnVuY3Rpb24gKHR5cGUpIHtcbiAgICByZXR1cm4gdHlwZS5zbGljZSgtMikgPT09ICdbXSc7XG59O1xuXG4vKipcbiAqIFNvbGlkaXR5VHlwZSBwcm90b3R5cGUgaXMgdXNlZCB0byBlbmNvZGUvZGVjb2RlIHNvbGlkaXR5IHBhcmFtcyBvZiBjZXJ0YWluIHR5cGVcbiAqL1xudmFyIFNvbGlkaXR5VHlwZSA9IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICB0aGlzLl9uYW1lID0gY29uZmlnLm5hbWU7XG4gICAgdGhpcy5fbWF0Y2ggPSBjb25maWcubWF0Y2g7XG4gICAgdGhpcy5fbW9kZSA9IGNvbmZpZy5tb2RlO1xuICAgIHRoaXMuX2lucHV0Rm9ybWF0dGVyID0gY29uZmlnLmlucHV0Rm9ybWF0dGVyO1xuICAgIHRoaXMuX291dHB1dEZvcm1hdHRlciA9IGNvbmZpZy5vdXRwdXRGb3JtYXR0ZXI7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGRldGVybWluZSBpZiB0aGlzIFNvbGlkaXR5VHlwZSBkbyBtYXRjaCBnaXZlbiB0eXBlXG4gKlxuICogQG1ldGhvZCBpc1R5cGVcbiAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lXG4gKiBAcmV0dXJuIHtCb29sfSB0cnVlIGlmIHR5cGUgbWF0Y2ggdGhpcyBTb2xpZGl0eVR5cGUsIG90aGVyd2lzZSBmYWxzZVxuICovXG5Tb2xpZGl0eVR5cGUucHJvdG90eXBlLmlzVHlwZSA9IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgaWYgKHRoaXMuX21hdGNoID09PSAnc3RyaWN0Jykge1xuICAgICAgICByZXR1cm4gdGhpcy5fbmFtZSA9PT0gbmFtZSB8fCAobmFtZS5pbmRleE9mKHRoaXMuX25hbWUpID09PSAwICYmIG5hbWUuc2xpY2UodGhpcy5fbmFtZS5sZW5ndGgpID09PSAnW10nKTtcbiAgICB9IGVsc2UgaWYgKHRoaXMuX21hdGNoID09PSAncHJlZml4Jykge1xuICAgICAgICAvLyBUT0RPIGJldHRlciB0eXBlIGRldGVjdGlvbiFcbiAgICAgICAgcmV0dXJuIG5hbWUuaW5kZXhPZih0aGlzLl9uYW1lKSA9PT0gMDtcbiAgICB9XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIHRyYW5zZm9ybSBwbGFpbiBwYXJhbSB0byBTb2xpZGl0eVBhcmFtIG9iamVjdFxuICpcbiAqIEBtZXRob2QgZm9ybWF0SW5wdXRcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYXJhbSAtIHBsYWluIG9iamVjdCwgb3IgYW4gYXJyYXkgb2Ygb2JqZWN0c1xuICogQHBhcmFtIHtCb29sfSBhcnJheVR5cGUgLSB0cnVlIGlmIGEgcGFyYW0gc2hvdWxkIGJlIGVuY29kZWQgYXMgYW4gYXJyYXlcbiAqIEByZXR1cm4ge1NvbGlkaXR5UGFyYW19IGVuY29kZWQgcGFyYW0gd3JhcHBlZCBpbiBTb2xpZGl0eVBhcmFtIG9iamVjdCBcbiAqL1xuU29saWRpdHlUeXBlLnByb3RvdHlwZS5mb3JtYXRJbnB1dCA9IGZ1bmN0aW9uIChwYXJhbSwgYXJyYXlUeXBlKSB7XG4gICAgaWYgKHV0aWxzLmlzQXJyYXkocGFyYW0pICYmIGFycmF5VHlwZSkgeyAvLyBUT0RPOiBzaG91bGQgZmFpbCBpZiB0aGlzIHR3byBhcmUgbm90IHRoZSBzYW1lXG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgcmV0dXJuIHBhcmFtLm1hcChmdW5jdGlvbiAocCkge1xuICAgICAgICAgICAgcmV0dXJuIHNlbGYuX2lucHV0Rm9ybWF0dGVyKHApO1xuICAgICAgICB9KS5yZWR1Y2UoZnVuY3Rpb24gKGFjYywgY3VycmVudCkge1xuICAgICAgICAgICAgcmV0dXJuIGFjYy5jb21iaW5lKGN1cnJlbnQpO1xuICAgICAgICB9LCBmLmZvcm1hdElucHV0SW50KHBhcmFtLmxlbmd0aCkpLndpdGhPZmZzZXQoMzIpO1xuICAgIH0gXG4gICAgcmV0dXJuIHRoaXMuX2lucHV0Rm9ybWF0dGVyKHBhcmFtKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gdHJhbnNvZm9ybSBTb2xpZGl0eVBhcmFtIHRvIHBsYWluIHBhcmFtXG4gKlxuICogQG1ldGhvZCBmb3JtYXRPdXRwdXRcbiAqIEBwYXJhbSB7U29saWRpdHlQYXJhbX0gYnl0ZUFycmF5XG4gKiBAcGFyYW0ge0Jvb2x9IGFycmF5VHlwZSAtIHRydWUgaWYgYSBwYXJhbSBzaG91bGQgYmUgZGVjb2RlZCBhcyBhbiBhcnJheVxuICogQHJldHVybiB7T2JqZWN0fSBwbGFpbiBkZWNvZGVkIHBhcmFtXG4gKi9cblNvbGlkaXR5VHlwZS5wcm90b3R5cGUuZm9ybWF0T3V0cHV0ID0gZnVuY3Rpb24gKHBhcmFtLCBhcnJheVR5cGUpIHtcbiAgICBpZiAoYXJyYXlUeXBlKSB7XG4gICAgICAgIC8vIGxldCdzIGFzc3VtZSwgdGhhdCB3ZSBzb2xpZGl0eSB3aWxsIG5ldmVyIHJldHVybiBsb25nIGFycmF5cyA6UCBcbiAgICAgICAgdmFyIHJlc3VsdCA9IFtdO1xuICAgICAgICB2YXIgbGVuZ3RoID0gbmV3IEJpZ051bWJlcihwYXJhbS5keW5hbWljUGFydCgpLnNsaWNlKDAsIDY0KSwgMTYpO1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aCAqIDY0OyBpICs9IDY0KSB7XG4gICAgICAgICAgICByZXN1bHQucHVzaCh0aGlzLl9vdXRwdXRGb3JtYXR0ZXIobmV3IFNvbGlkaXR5UGFyYW0ocGFyYW0uZHluYW1pY1BhcnQoKS5zdWJzdHIoaSArIDY0LCA2NCkpKSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuX291dHB1dEZvcm1hdHRlcihwYXJhbSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIHNsaWNlIHNpbmdsZSBwYXJhbSBmcm9tIGJ5dGVzXG4gKlxuICogQG1ldGhvZCBzbGljZVBhcmFtXG4gKiBAcGFyYW0ge1N0cmluZ30gYnl0ZXNcbiAqIEBwYXJhbSB7TnVtYmVyfSBpbmRleCBvZiBwYXJhbSB0byBzbGljZVxuICogQHBhcmFtIHtTdHJpbmd9IHR5cGVcbiAqIEByZXR1cm5zIHtTb2xpZGl0eVBhcmFtfSBwYXJhbVxuICovXG5Tb2xpZGl0eVR5cGUucHJvdG90eXBlLnNsaWNlUGFyYW0gPSBmdW5jdGlvbiAoYnl0ZXMsIGluZGV4LCB0eXBlKSB7XG4gICAgaWYgKHRoaXMuX21vZGUgPT09ICdieXRlcycpIHtcbiAgICAgICAgcmV0dXJuIFNvbGlkaXR5UGFyYW0uZGVjb2RlQnl0ZXMoYnl0ZXMsIGluZGV4KTtcbiAgICB9IGVsc2UgaWYgKGlzQXJyYXlUeXBlKHR5cGUpKSB7XG4gICAgICAgIHJldHVybiBTb2xpZGl0eVBhcmFtLmRlY29kZUFycmF5KGJ5dGVzLCBpbmRleCk7XG4gICAgfVxuICAgIHJldHVybiBTb2xpZGl0eVBhcmFtLmRlY29kZVBhcmFtKGJ5dGVzLCBpbmRleCk7XG59O1xuXG4vKipcbiAqIFNvbGlkaXR5Q29kZXIgcHJvdG90eXBlIHNob3VsZCBiZSB1c2VkIHRvIGVuY29kZS9kZWNvZGUgc29saWRpdHkgcGFyYW1zIG9mIGFueSB0eXBlXG4gKi9cbnZhciBTb2xpZGl0eUNvZGVyID0gZnVuY3Rpb24gKHR5cGVzKSB7XG4gICAgdGhpcy5fdHlwZXMgPSB0eXBlcztcbn07XG5cbi8qKlxuICogVGhpcyBtZXRob2Qgc2hvdWxkIGJlIHVzZWQgdG8gdHJhbnNmb3JtIHR5cGUgdG8gU29saWRpdHlUeXBlXG4gKlxuICogQG1ldGhvZCBfcmVxdWlyZVR5cGVcbiAqIEBwYXJhbSB7U3RyaW5nfSB0eXBlXG4gKiBAcmV0dXJucyB7U29saWRpdHlUeXBlfSBcbiAqIEB0aHJvd3Mge0Vycm9yfSB0aHJvd3MgaWYgbm8gbWF0Y2hpbmcgdHlwZSBpcyBmb3VuZFxuICovXG5Tb2xpZGl0eUNvZGVyLnByb3RvdHlwZS5fcmVxdWlyZVR5cGUgPSBmdW5jdGlvbiAodHlwZSkge1xuICAgIHZhciBzb2xpZGl0eVR5cGUgPSB0aGlzLl90eXBlcy5maWx0ZXIoZnVuY3Rpb24gKHQpIHtcbiAgICAgICAgcmV0dXJuIHQuaXNUeXBlKHR5cGUpO1xuICAgIH0pWzBdO1xuXG4gICAgaWYgKCFzb2xpZGl0eVR5cGUpIHtcbiAgICAgICAgdGhyb3cgRXJyb3IoJ2ludmFsaWQgc29saWRpdHkgdHlwZSE6ICcgKyB0eXBlKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc29saWRpdHlUeXBlO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byB0cmFuc2Zvcm0gcGxhaW4gcGFyYW0gb2YgZ2l2ZW4gdHlwZSB0byBTb2xpZGl0eVBhcmFtXG4gKlxuICogQG1ldGhvZCBfZm9ybWF0SW5wdXRcbiAqIEBwYXJhbSB7U3RyaW5nfSB0eXBlIG9mIHBhcmFtXG4gKiBAcGFyYW0ge09iamVjdH0gcGxhaW4gcGFyYW1cbiAqIEByZXR1cm4ge1NvbGlkaXR5UGFyYW19XG4gKi9cblNvbGlkaXR5Q29kZXIucHJvdG90eXBlLl9mb3JtYXRJbnB1dCA9IGZ1bmN0aW9uICh0eXBlLCBwYXJhbSkge1xuICAgIHJldHVybiB0aGlzLl9yZXF1aXJlVHlwZSh0eXBlKS5mb3JtYXRJbnB1dChwYXJhbSwgaXNBcnJheVR5cGUodHlwZSkpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBlbmNvZGUgcGxhaW4gcGFyYW1cbiAqXG4gKiBAbWV0aG9kIGVuY29kZVBhcmFtXG4gKiBAcGFyYW0ge1N0cmluZ30gdHlwZVxuICogQHBhcmFtIHtPYmplY3R9IHBsYWluIHBhcmFtXG4gKiBAcmV0dXJuIHtTdHJpbmd9IGVuY29kZWQgcGxhaW4gcGFyYW1cbiAqL1xuU29saWRpdHlDb2Rlci5wcm90b3R5cGUuZW5jb2RlUGFyYW0gPSBmdW5jdGlvbiAodHlwZSwgcGFyYW0pIHtcbiAgICByZXR1cm4gdGhpcy5fZm9ybWF0SW5wdXQodHlwZSwgcGFyYW0pLmVuY29kZSgpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBlbmNvZGUgbGlzdCBvZiBwYXJhbXNcbiAqXG4gKiBAbWV0aG9kIGVuY29kZVBhcmFtc1xuICogQHBhcmFtIHtBcnJheX0gdHlwZXNcbiAqIEBwYXJhbSB7QXJyYXl9IHBhcmFtc1xuICogQHJldHVybiB7U3RyaW5nfSBlbmNvZGVkIGxpc3Qgb2YgcGFyYW1zXG4gKi9cblNvbGlkaXR5Q29kZXIucHJvdG90eXBlLmVuY29kZVBhcmFtcyA9IGZ1bmN0aW9uICh0eXBlcywgcGFyYW1zKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHZhciBzb2xpZGl0eVBhcmFtcyA9IHR5cGVzLm1hcChmdW5jdGlvbiAodHlwZSwgaW5kZXgpIHtcbiAgICAgICAgcmV0dXJuIHNlbGYuX2Zvcm1hdElucHV0KHR5cGUsIHBhcmFtc1tpbmRleF0pO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIFNvbGlkaXR5UGFyYW0uZW5jb2RlTGlzdChzb2xpZGl0eVBhcmFtcyk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGRlY29kZSBieXRlcyB0byBwbGFpbiBwYXJhbVxuICpcbiAqIEBtZXRob2QgZGVjb2RlUGFyYW1cbiAqIEBwYXJhbSB7U3RyaW5nfSB0eXBlXG4gKiBAcGFyYW0ge1N0cmluZ30gYnl0ZXNcbiAqIEByZXR1cm4ge09iamVjdH0gcGxhaW4gcGFyYW1cbiAqL1xuU29saWRpdHlDb2Rlci5wcm90b3R5cGUuZGVjb2RlUGFyYW0gPSBmdW5jdGlvbiAodHlwZSwgYnl0ZXMpIHtcbiAgICByZXR1cm4gdGhpcy5kZWNvZGVQYXJhbXMoW3R5cGVdLCBieXRlcylbMF07XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGRlY29kZSBsaXN0IG9mIHBhcmFtc1xuICpcbiAqIEBtZXRob2QgZGVjb2RlUGFyYW1cbiAqIEBwYXJhbSB7QXJyYXl9IHR5cGVzXG4gKiBAcGFyYW0ge1N0cmluZ30gYnl0ZXNcbiAqIEByZXR1cm4ge0FycmF5fSBhcnJheSBvZiBwbGFpbiBwYXJhbXNcbiAqL1xuU29saWRpdHlDb2Rlci5wcm90b3R5cGUuZGVjb2RlUGFyYW1zID0gZnVuY3Rpb24gKHR5cGVzLCBieXRlcykge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICByZXR1cm4gdHlwZXMubWFwKGZ1bmN0aW9uICh0eXBlLCBpbmRleCkge1xuICAgICAgICB2YXIgc29saWRpdHlUeXBlID0gc2VsZi5fcmVxdWlyZVR5cGUodHlwZSk7XG4gICAgICAgIHZhciBwID0gc29saWRpdHlUeXBlLnNsaWNlUGFyYW0oYnl0ZXMsIGluZGV4LCB0eXBlKTtcbiAgICAgICAgcmV0dXJuIHNvbGlkaXR5VHlwZS5mb3JtYXRPdXRwdXQocCwgaXNBcnJheVR5cGUodHlwZSkpO1xuICAgIH0pO1xufTtcblxudmFyIGNvZGVyID0gbmV3IFNvbGlkaXR5Q29kZXIoW1xuICAgIG5ldyBTb2xpZGl0eVR5cGUoe1xuICAgICAgICBuYW1lOiAnYWRkcmVzcycsXG4gICAgICAgIG1hdGNoOiAnc3RyaWN0JyxcbiAgICAgICAgbW9kZTogJ3ZhbHVlJyxcbiAgICAgICAgaW5wdXRGb3JtYXR0ZXI6IGYuZm9ybWF0SW5wdXRJbnQsXG4gICAgICAgIG91dHB1dEZvcm1hdHRlcjogZi5mb3JtYXRPdXRwdXRBZGRyZXNzXG4gICAgfSksXG4gICAgbmV3IFNvbGlkaXR5VHlwZSh7XG4gICAgICAgIG5hbWU6ICdib29sJyxcbiAgICAgICAgbWF0Y2g6ICdzdHJpY3QnLFxuICAgICAgICBtb2RlOiAndmFsdWUnLFxuICAgICAgICBpbnB1dEZvcm1hdHRlcjogZi5mb3JtYXRJbnB1dEJvb2wsXG4gICAgICAgIG91dHB1dEZvcm1hdHRlcjogZi5mb3JtYXRPdXRwdXRCb29sXG4gICAgfSksXG4gICAgbmV3IFNvbGlkaXR5VHlwZSh7XG4gICAgICAgIG5hbWU6ICdpbnQnLFxuICAgICAgICBtYXRjaDogJ3ByZWZpeCcsXG4gICAgICAgIG1vZGU6ICd2YWx1ZScsXG4gICAgICAgIGlucHV0Rm9ybWF0dGVyOiBmLmZvcm1hdElucHV0SW50LFxuICAgICAgICBvdXRwdXRGb3JtYXR0ZXI6IGYuZm9ybWF0T3V0cHV0SW50LFxuICAgIH0pLFxuICAgIG5ldyBTb2xpZGl0eVR5cGUoe1xuICAgICAgICBuYW1lOiAndWludCcsXG4gICAgICAgIG1hdGNoOiAncHJlZml4JyxcbiAgICAgICAgbW9kZTogJ3ZhbHVlJyxcbiAgICAgICAgaW5wdXRGb3JtYXR0ZXI6IGYuZm9ybWF0SW5wdXRJbnQsXG4gICAgICAgIG91dHB1dEZvcm1hdHRlcjogZi5mb3JtYXRPdXRwdXRVSW50XG4gICAgfSksXG4gICAgbmV3IFNvbGlkaXR5VHlwZSh7XG4gICAgICAgIG5hbWU6ICdieXRlcycsXG4gICAgICAgIG1hdGNoOiAnc3RyaWN0JyxcbiAgICAgICAgbW9kZTogJ2J5dGVzJyxcbiAgICAgICAgaW5wdXRGb3JtYXR0ZXI6IGYuZm9ybWF0SW5wdXREeW5hbWljQnl0ZXMsXG4gICAgICAgIG91dHB1dEZvcm1hdHRlcjogZi5mb3JtYXRPdXRwdXREeW5hbWljQnl0ZXNcbiAgICB9KSxcbiAgICBuZXcgU29saWRpdHlUeXBlKHtcbiAgICAgICAgbmFtZTogJ2J5dGVzJyxcbiAgICAgICAgbWF0Y2g6ICdwcmVmaXgnLFxuICAgICAgICBtb2RlOiAndmFsdWUnLFxuICAgICAgICBpbnB1dEZvcm1hdHRlcjogZi5mb3JtYXRJbnB1dEJ5dGVzLFxuICAgICAgICBvdXRwdXRGb3JtYXR0ZXI6IGYuZm9ybWF0T3V0cHV0Qnl0ZXNcbiAgICB9KSxcbiAgICBuZXcgU29saWRpdHlUeXBlKHtcbiAgICAgICAgbmFtZTogJ3JlYWwnLFxuICAgICAgICBtYXRjaDogJ3ByZWZpeCcsXG4gICAgICAgIG1vZGU6ICd2YWx1ZScsXG4gICAgICAgIGlucHV0Rm9ybWF0dGVyOiBmLmZvcm1hdElucHV0UmVhbCxcbiAgICAgICAgb3V0cHV0Rm9ybWF0dGVyOiBmLmZvcm1hdE91dHB1dFJlYWxcbiAgICB9KSxcbiAgICBuZXcgU29saWRpdHlUeXBlKHtcbiAgICAgICAgbmFtZTogJ3VyZWFsJyxcbiAgICAgICAgbWF0Y2g6ICdwcmVmaXgnLFxuICAgICAgICBtb2RlOiAndmFsdWUnLFxuICAgICAgICBpbnB1dEZvcm1hdHRlcjogZi5mb3JtYXRJbnB1dFJlYWwsXG4gICAgICAgIG91dHB1dEZvcm1hdHRlcjogZi5mb3JtYXRPdXRwdXRVUmVhbFxuICAgIH0pXG5dKTtcblxubW9kdWxlLmV4cG9ydHMgPSBjb2RlcjtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogXG4gKiBAZmlsZSBmb3JtYXR0ZXJzLmpzXG4gKiBAYXV0aG9yIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbnZhciBCaWdOdW1iZXIgPSByZXF1aXJlKCdiaWdudW1iZXIuanMnKTtcbnZhciB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzL3V0aWxzJyk7XG52YXIgYyA9IHJlcXVpcmUoJy4uL3V0aWxzL2NvbmZpZycpO1xudmFyIFNvbGlkaXR5UGFyYW0gPSByZXF1aXJlKCcuL3BhcmFtJyk7XG5cblxuLyoqXG4gKiBGb3JtYXRzIGlucHV0IHZhbHVlIHRvIGJ5dGUgcmVwcmVzZW50YXRpb24gb2YgaW50XG4gKiBJZiB2YWx1ZSBpcyBuZWdhdGl2ZSwgcmV0dXJuIGl0J3MgdHdvJ3MgY29tcGxlbWVudFxuICogSWYgdGhlIHZhbHVlIGlzIGZsb2F0aW5nIHBvaW50LCByb3VuZCBpdCBkb3duXG4gKlxuICogQG1ldGhvZCBmb3JtYXRJbnB1dEludFxuICogQHBhcmFtIHtTdHJpbmd8TnVtYmVyfEJpZ051bWJlcn0gdmFsdWUgdGhhdCBuZWVkcyB0byBiZSBmb3JtYXR0ZWRcbiAqIEByZXR1cm5zIHtTb2xpZGl0eVBhcmFtfVxuICovXG52YXIgZm9ybWF0SW5wdXRJbnQgPSBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICB2YXIgcGFkZGluZyA9IGMuRVRIX1BBRERJTkcgKiAyO1xuICAgIEJpZ051bWJlci5jb25maWcoYy5FVEhfQklHTlVNQkVSX1JPVU5ESU5HX01PREUpO1xuICAgIHZhciByZXN1bHQgPSB1dGlscy5wYWRMZWZ0KHV0aWxzLnRvVHdvc0NvbXBsZW1lbnQodmFsdWUpLnJvdW5kKCkudG9TdHJpbmcoMTYpLCBwYWRkaW5nKTtcbiAgICByZXR1cm4gbmV3IFNvbGlkaXR5UGFyYW0ocmVzdWx0KTtcbn07XG5cbi8qKlxuICogRm9ybWF0cyBpbnB1dCB2YWx1ZSB0byBieXRlIHJlcHJlc2VudGF0aW9uIG9mIHN0cmluZ1xuICpcbiAqIEBtZXRob2QgZm9ybWF0SW5wdXRCeXRlc1xuICogQHBhcmFtIHtTdHJpbmd9XG4gKiBAcmV0dXJucyB7U29saWRpdHlQYXJhbX1cbiAqL1xudmFyIGZvcm1hdElucHV0Qnl0ZXMgPSBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICB2YXIgcmVzdWx0ID0gdXRpbHMuZnJvbUFzY2lpKHZhbHVlLCBjLkVUSF9QQURESU5HKS5zdWJzdHIoMik7XG4gICAgcmV0dXJuIG5ldyBTb2xpZGl0eVBhcmFtKHJlc3VsdCk7XG59O1xuXG4vKipcbiAqIEZvcm1hdHMgaW5wdXQgdmFsdWUgdG8gYnl0ZSByZXByZXNlbnRhdGlvbiBvZiBzdHJpbmdcbiAqXG4gKiBAbWV0aG9kIGZvcm1hdElucHV0RHluYW1pY0J5dGVzXG4gKiBAcGFyYW0ge1N0cmluZ31cbiAqIEByZXR1cm5zIHtTb2xpZGl0eVBhcmFtfVxuICovXG52YXIgZm9ybWF0SW5wdXREeW5hbWljQnl0ZXMgPSBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICB2YXIgcmVzdWx0ID0gdXRpbHMuZnJvbUFzY2lpKHZhbHVlLCBjLkVUSF9QQURESU5HKS5zdWJzdHIoMik7XG4gICAgcmV0dXJuIG5ldyBTb2xpZGl0eVBhcmFtKGZvcm1hdElucHV0SW50KHZhbHVlLmxlbmd0aCkudmFsdWUgKyByZXN1bHQsIDMyKTtcbn07XG5cbi8qKlxuICogRm9ybWF0cyBpbnB1dCB2YWx1ZSB0byBieXRlIHJlcHJlc2VudGF0aW9uIG9mIGJvb2xcbiAqXG4gKiBAbWV0aG9kIGZvcm1hdElucHV0Qm9vbFxuICogQHBhcmFtIHtCb29sZWFufVxuICogQHJldHVybnMge1NvbGlkaXR5UGFyYW19XG4gKi9cbnZhciBmb3JtYXRJbnB1dEJvb2wgPSBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICB2YXIgcmVzdWx0ID0gJzAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMCcgKyAodmFsdWUgPyAgJzEnIDogJzAnKTtcbiAgICByZXR1cm4gbmV3IFNvbGlkaXR5UGFyYW0ocmVzdWx0KTtcbn07XG5cbi8qKlxuICogRm9ybWF0cyBpbnB1dCB2YWx1ZSB0byBieXRlIHJlcHJlc2VudGF0aW9uIG9mIHJlYWxcbiAqIFZhbHVlcyBhcmUgbXVsdGlwbGllZCBieSAyXm0gYW5kIGVuY29kZWQgYXMgaW50ZWdlcnNcbiAqXG4gKiBAbWV0aG9kIGZvcm1hdElucHV0UmVhbFxuICogQHBhcmFtIHtTdHJpbmd8TnVtYmVyfEJpZ051bWJlcn1cbiAqIEByZXR1cm5zIHtTb2xpZGl0eVBhcmFtfVxuICovXG52YXIgZm9ybWF0SW5wdXRSZWFsID0gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgcmV0dXJuIGZvcm1hdElucHV0SW50KG5ldyBCaWdOdW1iZXIodmFsdWUpLnRpbWVzKG5ldyBCaWdOdW1iZXIoMikucG93KDEyOCkpKTtcbn07XG5cbi8qKlxuICogQ2hlY2sgaWYgaW5wdXQgdmFsdWUgaXMgbmVnYXRpdmVcbiAqXG4gKiBAbWV0aG9kIHNpZ25lZElzTmVnYXRpdmVcbiAqIEBwYXJhbSB7U3RyaW5nfSB2YWx1ZSBpcyBoZXggZm9ybWF0XG4gKiBAcmV0dXJucyB7Qm9vbGVhbn0gdHJ1ZSBpZiBpdCBpcyBuZWdhdGl2ZSwgb3RoZXJ3aXNlIGZhbHNlXG4gKi9cbnZhciBzaWduZWRJc05lZ2F0aXZlID0gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgcmV0dXJuIChuZXcgQmlnTnVtYmVyKHZhbHVlLnN1YnN0cigwLCAxKSwgMTYpLnRvU3RyaW5nKDIpLnN1YnN0cigwLCAxKSkgPT09ICcxJztcbn07XG5cbi8qKlxuICogRm9ybWF0cyByaWdodC1hbGlnbmVkIG91dHB1dCBieXRlcyB0byBpbnRcbiAqXG4gKiBAbWV0aG9kIGZvcm1hdE91dHB1dEludFxuICogQHBhcmFtIHtTb2xpZGl0eVBhcmFtfSBwYXJhbVxuICogQHJldHVybnMge0JpZ051bWJlcn0gcmlnaHQtYWxpZ25lZCBvdXRwdXQgYnl0ZXMgZm9ybWF0dGVkIHRvIGJpZyBudW1iZXJcbiAqL1xudmFyIGZvcm1hdE91dHB1dEludCA9IGZ1bmN0aW9uIChwYXJhbSkge1xuICAgIHZhciB2YWx1ZSA9IHBhcmFtLnN0YXRpY1BhcnQoKSB8fCBcIjBcIjtcblxuICAgIC8vIGNoZWNrIGlmIGl0J3MgbmVnYXRpdmUgbnVtYmVyXG4gICAgLy8gaXQgaXQgaXMsIHJldHVybiB0d28ncyBjb21wbGVtZW50XG4gICAgaWYgKHNpZ25lZElzTmVnYXRpdmUodmFsdWUpKSB7XG4gICAgICAgIHJldHVybiBuZXcgQmlnTnVtYmVyKHZhbHVlLCAxNikubWludXMobmV3IEJpZ051bWJlcignZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZicsIDE2KSkubWludXMoMSk7XG4gICAgfVxuICAgIHJldHVybiBuZXcgQmlnTnVtYmVyKHZhbHVlLCAxNik7XG59O1xuXG4vKipcbiAqIEZvcm1hdHMgcmlnaHQtYWxpZ25lZCBvdXRwdXQgYnl0ZXMgdG8gdWludFxuICpcbiAqIEBtZXRob2QgZm9ybWF0T3V0cHV0VUludFxuICogQHBhcmFtIHtTb2xpZGl0eVBhcmFtfVxuICogQHJldHVybnMge0JpZ051bWViZXJ9IHJpZ2h0LWFsaWduZWQgb3V0cHV0IGJ5dGVzIGZvcm1hdHRlZCB0byB1aW50XG4gKi9cbnZhciBmb3JtYXRPdXRwdXRVSW50ID0gZnVuY3Rpb24gKHBhcmFtKSB7XG4gICAgdmFyIHZhbHVlID0gcGFyYW0uc3RhdGljUGFydCgpIHx8IFwiMFwiO1xuICAgIHJldHVybiBuZXcgQmlnTnVtYmVyKHZhbHVlLCAxNik7XG59O1xuXG4vKipcbiAqIEZvcm1hdHMgcmlnaHQtYWxpZ25lZCBvdXRwdXQgYnl0ZXMgdG8gcmVhbFxuICpcbiAqIEBtZXRob2QgZm9ybWF0T3V0cHV0UmVhbFxuICogQHBhcmFtIHtTb2xpZGl0eVBhcmFtfVxuICogQHJldHVybnMge0JpZ051bWJlcn0gaW5wdXQgYnl0ZXMgZm9ybWF0dGVkIHRvIHJlYWxcbiAqL1xudmFyIGZvcm1hdE91dHB1dFJlYWwgPSBmdW5jdGlvbiAocGFyYW0pIHtcbiAgICByZXR1cm4gZm9ybWF0T3V0cHV0SW50KHBhcmFtKS5kaXZpZGVkQnkobmV3IEJpZ051bWJlcigyKS5wb3coMTI4KSk7IFxufTtcblxuLyoqXG4gKiBGb3JtYXRzIHJpZ2h0LWFsaWduZWQgb3V0cHV0IGJ5dGVzIHRvIHVyZWFsXG4gKlxuICogQG1ldGhvZCBmb3JtYXRPdXRwdXRVUmVhbFxuICogQHBhcmFtIHtTb2xpZGl0eVBhcmFtfVxuICogQHJldHVybnMge0JpZ051bWJlcn0gaW5wdXQgYnl0ZXMgZm9ybWF0dGVkIHRvIHVyZWFsXG4gKi9cbnZhciBmb3JtYXRPdXRwdXRVUmVhbCA9IGZ1bmN0aW9uIChwYXJhbSkge1xuICAgIHJldHVybiBmb3JtYXRPdXRwdXRVSW50KHBhcmFtKS5kaXZpZGVkQnkobmV3IEJpZ051bWJlcigyKS5wb3coMTI4KSk7IFxufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBmb3JtYXQgb3V0cHV0IGJvb2xcbiAqXG4gKiBAbWV0aG9kIGZvcm1hdE91dHB1dEJvb2xcbiAqIEBwYXJhbSB7U29saWRpdHlQYXJhbX1cbiAqIEByZXR1cm5zIHtCb29sZWFufSByaWdodC1hbGlnbmVkIGlucHV0IGJ5dGVzIGZvcm1hdHRlZCB0byBib29sXG4gKi9cbnZhciBmb3JtYXRPdXRwdXRCb29sID0gZnVuY3Rpb24gKHBhcmFtKSB7XG4gICAgcmV0dXJuIHBhcmFtLnN0YXRpY1BhcnQoKSA9PT0gJzAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEnID8gdHJ1ZSA6IGZhbHNlO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBmb3JtYXQgb3V0cHV0IHN0cmluZ1xuICpcbiAqIEBtZXRob2QgZm9ybWF0T3V0cHV0Qnl0ZXNcbiAqIEBwYXJhbSB7U29saWRpdHlQYXJhbX0gbGVmdC1hbGlnbmVkIGhleCByZXByZXNlbnRhdGlvbiBvZiBzdHJpbmdcbiAqIEByZXR1cm5zIHtTdHJpbmd9IGFzY2lpIHN0cmluZ1xuICovXG52YXIgZm9ybWF0T3V0cHV0Qnl0ZXMgPSBmdW5jdGlvbiAocGFyYW0pIHtcbiAgICAvLyBsZW5ndGggbWlnaHQgYWxzbyBiZSBpbXBvcnRhbnQhXG4gICAgcmV0dXJuIHV0aWxzLnRvQXNjaWkocGFyYW0uc3RhdGljUGFydCgpKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZm9ybWF0IG91dHB1dCBzdHJpbmdcbiAqXG4gKiBAbWV0aG9kIGZvcm1hdE91dHB1dER5bmFtaWNCeXRlc1xuICogQHBhcmFtIHtTb2xpZGl0eVBhcmFtfSBsZWZ0LWFsaWduZWQgaGV4IHJlcHJlc2VudGF0aW9uIG9mIHN0cmluZ1xuICogQHJldHVybnMge1N0cmluZ30gYXNjaWkgc3RyaW5nXG4gKi9cbnZhciBmb3JtYXRPdXRwdXREeW5hbWljQnl0ZXMgPSBmdW5jdGlvbiAocGFyYW0pIHtcbiAgICAvLyBsZW5ndGggbWlnaHQgYWxzbyBiZSBpbXBvcnRhbnQhXG4gICAgcmV0dXJuIHV0aWxzLnRvQXNjaWkocGFyYW0uZHluYW1pY1BhcnQoKS5zbGljZSg2NCkpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBmb3JtYXQgb3V0cHV0IGFkZHJlc3NcbiAqXG4gKiBAbWV0aG9kIGZvcm1hdE91dHB1dEFkZHJlc3NcbiAqIEBwYXJhbSB7U29saWRpdHlQYXJhbX0gcmlnaHQtYWxpZ25lZCBpbnB1dCBieXRlc1xuICogQHJldHVybnMge1N0cmluZ30gYWRkcmVzc1xuICovXG52YXIgZm9ybWF0T3V0cHV0QWRkcmVzcyA9IGZ1bmN0aW9uIChwYXJhbSkge1xuICAgIHZhciB2YWx1ZSA9IHBhcmFtLnN0YXRpY1BhcnQoKTtcbiAgICByZXR1cm4gXCIweFwiICsgdmFsdWUuc2xpY2UodmFsdWUubGVuZ3RoIC0gNDAsIHZhbHVlLmxlbmd0aCk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBmb3JtYXRJbnB1dEludDogZm9ybWF0SW5wdXRJbnQsXG4gICAgZm9ybWF0SW5wdXRCeXRlczogZm9ybWF0SW5wdXRCeXRlcyxcbiAgICBmb3JtYXRJbnB1dER5bmFtaWNCeXRlczogZm9ybWF0SW5wdXREeW5hbWljQnl0ZXMsXG4gICAgZm9ybWF0SW5wdXRCb29sOiBmb3JtYXRJbnB1dEJvb2wsXG4gICAgZm9ybWF0SW5wdXRSZWFsOiBmb3JtYXRJbnB1dFJlYWwsXG4gICAgZm9ybWF0T3V0cHV0SW50OiBmb3JtYXRPdXRwdXRJbnQsXG4gICAgZm9ybWF0T3V0cHV0VUludDogZm9ybWF0T3V0cHV0VUludCxcbiAgICBmb3JtYXRPdXRwdXRSZWFsOiBmb3JtYXRPdXRwdXRSZWFsLFxuICAgIGZvcm1hdE91dHB1dFVSZWFsOiBmb3JtYXRPdXRwdXRVUmVhbCxcbiAgICBmb3JtYXRPdXRwdXRCb29sOiBmb3JtYXRPdXRwdXRCb29sLFxuICAgIGZvcm1hdE91dHB1dEJ5dGVzOiBmb3JtYXRPdXRwdXRCeXRlcyxcbiAgICBmb3JtYXRPdXRwdXREeW5hbWljQnl0ZXM6IGZvcm1hdE91dHB1dER5bmFtaWNCeXRlcyxcbiAgICBmb3JtYXRPdXRwdXRBZGRyZXNzOiBmb3JtYXRPdXRwdXRBZGRyZXNzXG59O1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBcbiAqIEBmaWxlIHBhcmFtLmpzXG4gKiBAYXV0aG9yIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbnZhciB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzL3V0aWxzJyk7XG5cbi8qKlxuICogU29saWRpdHlQYXJhbSBvYmplY3QgcHJvdG90eXBlLlxuICogU2hvdWxkIGJlIHVzZWQgd2hlbiBlbmNvZGluZywgZGVjb2Rpbmcgc29saWRpdHkgYnl0ZXNcbiAqL1xudmFyIFNvbGlkaXR5UGFyYW0gPSBmdW5jdGlvbiAodmFsdWUsIG9mZnNldCkge1xuICAgIHRoaXMudmFsdWUgPSB2YWx1ZSB8fCAnJztcbiAgICB0aGlzLm9mZnNldCA9IG9mZnNldDsgLy8gb2Zmc2V0IGluIGJ5dGVzXG59O1xuXG4vKipcbiAqIFRoaXMgbWV0aG9kIHNob3VsZCBiZSB1c2VkIHRvIGdldCBsZW5ndGggb2YgcGFyYW1zJ3MgZHluYW1pYyBwYXJ0XG4gKiBcbiAqIEBtZXRob2QgZHluYW1pY1BhcnRMZW5ndGhcbiAqIEByZXR1cm5zIHtOdW1iZXJ9IGxlbmd0aCBvZiBkeW5hbWljIHBhcnQgKGluIGJ5dGVzKVxuICovXG5Tb2xpZGl0eVBhcmFtLnByb3RvdHlwZS5keW5hbWljUGFydExlbmd0aCA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5keW5hbWljUGFydCgpLmxlbmd0aCAvIDI7XG59O1xuXG4vKipcbiAqIFRoaXMgbWV0aG9kIHNob3VsZCBiZSB1c2VkIHRvIGNyZWF0ZSBjb3B5IG9mIHNvbGlkaXR5IHBhcmFtIHdpdGggZGlmZmVyZW50IG9mZnNldFxuICpcbiAqIEBtZXRob2Qgd2l0aE9mZnNldFxuICogQHBhcmFtIHtOdW1iZXJ9IG9mZnNldCBsZW5ndGggaW4gYnl0ZXNcbiAqIEByZXR1cm5zIHtTb2xpZGl0eVBhcmFtfSBuZXcgc29saWRpdHkgcGFyYW0gd2l0aCBhcHBsaWVkIG9mZnNldFxuICovXG5Tb2xpZGl0eVBhcmFtLnByb3RvdHlwZS53aXRoT2Zmc2V0ID0gZnVuY3Rpb24gKG9mZnNldCkge1xuICAgIHJldHVybiBuZXcgU29saWRpdHlQYXJhbSh0aGlzLnZhbHVlLCBvZmZzZXQpO1xufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgdXNlZCB0byBjb21iaW5lIHNvbGlkaXR5IHBhcmFtcyB0b2dldGhlclxuICogZWcuIHdoZW4gYXBwZW5kaW5nIGFuIGFycmF5XG4gKlxuICogQG1ldGhvZCBjb21iaW5lXG4gKiBAcGFyYW0ge1NvbGlkaXR5UGFyYW19IHBhcmFtIHdpdGggd2hpY2ggd2Ugc2hvdWxkIGNvbWJpbmVcbiAqIEBwYXJhbSB7U29saWRpdHlQYXJhbX0gcmVzdWx0IG9mIGNvbWJpbmF0aW9uXG4gKi9cblNvbGlkaXR5UGFyYW0ucHJvdG90eXBlLmNvbWJpbmUgPSBmdW5jdGlvbiAocGFyYW0pIHtcbiAgICByZXR1cm4gbmV3IFNvbGlkaXR5UGFyYW0odGhpcy52YWx1ZSArIHBhcmFtLnZhbHVlKTsgXG59O1xuXG4vKipcbiAqIFRoaXMgbWV0aG9kIHNob3VsZCBiZSBjYWxsZWQgdG8gY2hlY2sgaWYgcGFyYW0gaGFzIGR5bmFtaWMgc2l6ZS5cbiAqIElmIGl0IGhhcywgaXQgcmV0dXJucyB0cnVlLCBvdGhlcndpc2UgZmFsc2VcbiAqXG4gKiBAbWV0aG9kIGlzRHluYW1pY1xuICogQHJldHVybnMge0Jvb2xlYW59XG4gKi9cblNvbGlkaXR5UGFyYW0ucHJvdG90eXBlLmlzRHluYW1pYyA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy52YWx1ZS5sZW5ndGggPiA2NCB8fCB0aGlzLm9mZnNldCAhPT0gdW5kZWZpbmVkO1xufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgY2FsbGVkIHRvIHRyYW5zZm9ybSBvZmZzZXQgdG8gYnl0ZXNcbiAqXG4gKiBAbWV0aG9kIG9mZnNldEFzQnl0ZXNcbiAqIEByZXR1cm5zIHtTdHJpbmd9IGJ5dGVzIHJlcHJlc2VudGF0aW9uIG9mIG9mZnNldFxuICovXG5Tb2xpZGl0eVBhcmFtLnByb3RvdHlwZS5vZmZzZXRBc0J5dGVzID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiAhdGhpcy5pc0R5bmFtaWMoKSA/ICcnIDogdXRpbHMucGFkTGVmdCh1dGlscy50b1R3b3NDb21wbGVtZW50KHRoaXMub2Zmc2V0KS50b1N0cmluZygxNiksIDY0KTtcbn07XG5cbi8qKlxuICogVGhpcyBtZXRob2Qgc2hvdWxkIGJlIGNhbGxlZCB0byBnZXQgc3RhdGljIHBhcnQgb2YgcGFyYW1cbiAqXG4gKiBAbWV0aG9kIHN0YXRpY1BhcnRcbiAqIEByZXR1cm5zIHtTdHJpbmd9IG9mZnNldCBpZiBpdCBpcyBhIGR5bmFtaWMgcGFyYW0sIG90aGVyd2lzZSB2YWx1ZVxuICovXG5Tb2xpZGl0eVBhcmFtLnByb3RvdHlwZS5zdGF0aWNQYXJ0ID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICghdGhpcy5pc0R5bmFtaWMoKSkge1xuICAgICAgICByZXR1cm4gdGhpcy52YWx1ZTsgXG4gICAgfSBcbiAgICByZXR1cm4gdGhpcy5vZmZzZXRBc0J5dGVzKCk7XG59O1xuXG4vKipcbiAqIFRoaXMgbWV0aG9kIHNob3VsZCBiZSBjYWxsZWQgdG8gZ2V0IGR5bmFtaWMgcGFydCBvZiBwYXJhbVxuICpcbiAqIEBtZXRob2QgZHluYW1pY1BhcnRcbiAqIEByZXR1cm5zIHtTdHJpbmd9IHJldHVybnMgYSB2YWx1ZSBpZiBpdCBpcyBhIGR5bmFtaWMgcGFyYW0sIG90aGVyd2lzZSBlbXB0eSBzdHJpbmdcbiAqL1xuU29saWRpdHlQYXJhbS5wcm90b3R5cGUuZHluYW1pY1BhcnQgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuaXNEeW5hbWljKCkgPyB0aGlzLnZhbHVlIDogJyc7XG59O1xuXG4vKipcbiAqIFRoaXMgbWV0aG9kIHNob3VsZCBiZSBjYWxsZWQgdG8gZW5jb2RlIHBhcmFtXG4gKlxuICogQG1ldGhvZCBlbmNvZGVcbiAqIEByZXR1cm5zIHtTdHJpbmd9XG4gKi9cblNvbGlkaXR5UGFyYW0ucHJvdG90eXBlLmVuY29kZSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5zdGF0aWNQYXJ0KCkgKyB0aGlzLmR5bmFtaWNQYXJ0KCk7XG59O1xuXG4vKipcbiAqIFRoaXMgbWV0aG9kIHNob3VsZCBiZSBjYWxsZWQgdG8gZW5jb2RlIGFycmF5IG9mIHBhcmFtc1xuICpcbiAqIEBtZXRob2QgZW5jb2RlTGlzdFxuICogQHBhcmFtIHtBcnJheVtTb2xpZGl0eVBhcmFtXX0gcGFyYW1zXG4gKiBAcmV0dXJucyB7U3RyaW5nfVxuICovXG5Tb2xpZGl0eVBhcmFtLmVuY29kZUxpc3QgPSBmdW5jdGlvbiAocGFyYW1zKSB7XG4gICAgXG4gICAgLy8gdXBkYXRpbmcgb2Zmc2V0c1xuICAgIHZhciB0b3RhbE9mZnNldCA9IHBhcmFtcy5sZW5ndGggKiAzMjtcbiAgICB2YXIgb2Zmc2V0UGFyYW1zID0gcGFyYW1zLm1hcChmdW5jdGlvbiAocGFyYW0pIHtcbiAgICAgICAgaWYgKCFwYXJhbS5pc0R5bmFtaWMoKSkge1xuICAgICAgICAgICAgcmV0dXJuIHBhcmFtO1xuICAgICAgICB9XG4gICAgICAgIHZhciBvZmZzZXQgPSB0b3RhbE9mZnNldDtcbiAgICAgICAgdG90YWxPZmZzZXQgKz0gcGFyYW0uZHluYW1pY1BhcnRMZW5ndGgoKTtcbiAgICAgICAgcmV0dXJuIHBhcmFtLndpdGhPZmZzZXQob2Zmc2V0KTtcbiAgICB9KTtcblxuICAgIC8vIGVuY29kZSBldmVyeXRoaW5nIVxuICAgIHJldHVybiBvZmZzZXRQYXJhbXMucmVkdWNlKGZ1bmN0aW9uIChyZXN1bHQsIHBhcmFtKSB7XG4gICAgICAgIHJldHVybiByZXN1bHQgKyBwYXJhbS5keW5hbWljUGFydCgpO1xuICAgIH0sIG9mZnNldFBhcmFtcy5yZWR1Y2UoZnVuY3Rpb24gKHJlc3VsdCwgcGFyYW0pIHtcbiAgICAgICAgcmV0dXJuIHJlc3VsdCArIHBhcmFtLnN0YXRpY1BhcnQoKTtcbiAgICB9LCAnJykpO1xufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgdXNlZCB0byBkZWNvZGUgcGxhaW4gKHN0YXRpYykgc29saWRpdHkgcGFyYW0gYXQgZ2l2ZW4gaW5kZXhcbiAqXG4gKiBAbWV0aG9kIGRlY29kZVBhcmFtXG4gKiBAcGFyYW0ge1N0cmluZ30gYnl0ZXNcbiAqIEBwYXJhbSB7TnVtYmVyfSBpbmRleFxuICogQHJldHVybnMge1NvbGlkaXR5UGFyYW19XG4gKi9cblNvbGlkaXR5UGFyYW0uZGVjb2RlUGFyYW0gPSBmdW5jdGlvbiAoYnl0ZXMsIGluZGV4KSB7XG4gICAgaW5kZXggPSBpbmRleCB8fCAwO1xuICAgIHJldHVybiBuZXcgU29saWRpdHlQYXJhbShieXRlcy5zdWJzdHIoaW5kZXggKiA2NCwgNjQpKTsgXG59O1xuXG4vKipcbiAqIFRoaXMgbWV0aG9kIHNob3VsZCBiZSBjYWxsZWQgdG8gZ2V0IG9mZnNldCB2YWx1ZSBmcm9tIGJ5dGVzIGF0IGdpdmVuIGluZGV4XG4gKlxuICogQG1ldGhvZCBnZXRPZmZzZXRcbiAqIEBwYXJhbSB7U3RyaW5nfSBieXRlc1xuICogQHBhcmFtIHtOdW1iZXJ9IGluZGV4XG4gKiBAcmV0dXJucyB7TnVtYmVyfSBvZmZzZXQgYXMgbnVtYmVyXG4gKi9cbnZhciBnZXRPZmZzZXQgPSBmdW5jdGlvbiAoYnl0ZXMsIGluZGV4KSB7XG4gICAgLy8gd2UgY2FuIGRvIHRoaXMgY2F1c2Ugb2Zmc2V0IGlzIHJhdGhlciBzbWFsbFxuICAgIHJldHVybiBwYXJzZUludCgnMHgnICsgYnl0ZXMuc3Vic3RyKGluZGV4ICogNjQsIDY0KSk7XG59O1xuXG4vKipcbiAqIFRoaXMgbWV0aG9kIHNob3VsZCBiZSBjYWxsZWQgdG8gZGVjb2RlIHNvbGlkaXR5IGJ5dGVzIHBhcmFtIGF0IGdpdmVuIGluZGV4XG4gKlxuICogQG1ldGhvZCBkZWNvZGVCeXRlc1xuICogQHBhcmFtIHtTdHJpbmd9IGJ5dGVzXG4gKiBAcGFyYW0ge051bWJlcn0gaW5kZXhcbiAqIEByZXR1cm5zIHtTb2xpZGl0eVBhcmFtfVxuICovXG5Tb2xpZGl0eVBhcmFtLmRlY29kZUJ5dGVzID0gZnVuY3Rpb24gKGJ5dGVzLCBpbmRleCkge1xuICAgIGluZGV4ID0gaW5kZXggfHwgMDtcbiAgICAvL1RPRE8gYWRkIHN1cHBvcnQgZm9yIHN0cmluZ3MgbG9uZ2VyIHRoYW4gMzIgYnl0ZXNcbiAgICAvL3ZhciBsZW5ndGggPSBwYXJzZUludCgnMHgnICsgYnl0ZXMuc3Vic3RyKG9mZnNldCAqIDY0LCA2NCkpO1xuXG4gICAgdmFyIG9mZnNldCA9IGdldE9mZnNldChieXRlcywgaW5kZXgpO1xuXG4gICAgLy8gMiAqICwgY2F1c2Ugd2UgYWxzbyBwYXJzZSBsZW5ndGhcbiAgICByZXR1cm4gbmV3IFNvbGlkaXR5UGFyYW0oYnl0ZXMuc3Vic3RyKG9mZnNldCAqIDIsIDIgKiA2NCksIDApO1xufTtcblxuLyoqXG4gKiBUaGlzIG1ldGhvZCBzaG91bGQgYmUgdXNlZCB0byBkZWNvZGUgc29saWRpdHkgYXJyYXkgYXQgZ2l2ZW4gaW5kZXhcbiAqXG4gKiBAbWV0aG9kIGRlY29kZUFycmF5XG4gKiBAcGFyYW0ge1N0cmluZ30gYnl0ZXNcbiAqIEBwYXJhbSB7TnVtYmVyfSBpbmRleFxuICogQHJldHVybnMge1NvbGlkaXR5UGFyYW19XG4gKi9cblNvbGlkaXR5UGFyYW0uZGVjb2RlQXJyYXkgPSBmdW5jdGlvbiAoYnl0ZXMsIGluZGV4KSB7XG4gICAgaW5kZXggPSBpbmRleCB8fCAwO1xuICAgIHZhciBvZmZzZXQgPSBnZXRPZmZzZXQoYnl0ZXMsIGluZGV4KTtcbiAgICB2YXIgbGVuZ3RoID0gcGFyc2VJbnQoJzB4JyArIGJ5dGVzLnN1YnN0cihvZmZzZXQgKiAyLCA2NCkpO1xuICAgIHJldHVybiBuZXcgU29saWRpdHlQYXJhbShieXRlcy5zdWJzdHIob2Zmc2V0ICogMiwgKGxlbmd0aCArIDEpICogNjQpLCAwKTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gU29saWRpdHlQYXJhbTtcblxuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyBnbyBlbnYgZG9lc24ndCBoYXZlIGFuZCBuZWVkIFhNTEh0dHBSZXF1ZXN0XG5pZiAodHlwZW9mIFhNTEh0dHBSZXF1ZXN0ID09PSAndW5kZWZpbmVkJykge1xuICAgIGV4cG9ydHMuWE1MSHR0cFJlcXVlc3QgPSB7fTtcbn0gZWxzZSB7XG4gICAgZXhwb3J0cy5YTUxIdHRwUmVxdWVzdCA9IFhNTEh0dHBSZXF1ZXN0OyAvLyBqc2hpbnQgaWdub3JlOmxpbmVcbn1cblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogQGZpbGUgY29uZmlnLmpzXG4gKiBAYXV0aG9yczpcbiAqICAgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE1XG4gKi9cblxuLyoqXG4gKiBVdGlsc1xuICogXG4gKiBAbW9kdWxlIHV0aWxzXG4gKi9cblxuLyoqXG4gKiBVdGlsaXR5IGZ1bmN0aW9uc1xuICogXG4gKiBAY2xhc3MgW3V0aWxzXSBjb25maWdcbiAqIEBjb25zdHJ1Y3RvclxuICovXG5cbi8vLyByZXF1aXJlZCB0byBkZWZpbmUgRVRIX0JJR05VTUJFUl9ST1VORElOR19NT0RFXG52YXIgQmlnTnVtYmVyID0gcmVxdWlyZSgnYmlnbnVtYmVyLmpzJyk7XG5cbnZhciBFVEhfVU5JVFMgPSBbXG4gICAgJ3dlaScsXG4gICAgJ2t3ZWknLFxuICAgICdNd2VpJyxcbiAgICAnR3dlaScsXG4gICAgJ3N6YWJvJyxcbiAgICAnZmlubmV5JyxcbiAgICAnZmVtdG9ldGhlcicsXG4gICAgJ3BpY29ldGhlcicsXG4gICAgJ25hbm9ldGhlcicsXG4gICAgJ21pY3JvZXRoZXInLFxuICAgICdtaWxsaWV0aGVyJyxcbiAgICAnbmFubycsXG4gICAgJ21pY3JvJyxcbiAgICAnbWlsbGknLFxuICAgICdldGhlcicsXG4gICAgJ2dyYW5kJyxcbiAgICAnTWV0aGVyJyxcbiAgICAnR2V0aGVyJyxcbiAgICAnVGV0aGVyJyxcbiAgICAnUGV0aGVyJyxcbiAgICAnRWV0aGVyJyxcbiAgICAnWmV0aGVyJyxcbiAgICAnWWV0aGVyJyxcbiAgICAnTmV0aGVyJyxcbiAgICAnRGV0aGVyJyxcbiAgICAnVmV0aGVyJyxcbiAgICAnVWV0aGVyJ1xuXTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgRVRIX1BBRERJTkc6IDMyLFxuICAgIEVUSF9TSUdOQVRVUkVfTEVOR1RIOiA0LFxuICAgIEVUSF9VTklUUzogRVRIX1VOSVRTLFxuICAgIEVUSF9CSUdOVU1CRVJfUk9VTkRJTkdfTU9ERTogeyBST1VORElOR19NT0RFOiBCaWdOdW1iZXIuUk9VTkRfRE9XTiB9LFxuICAgIEVUSF9QT0xMSU5HX1RJTUVPVVQ6IDEwMDAsXG4gICAgZGVmYXVsdEJsb2NrOiAnbGF0ZXN0JyxcbiAgICBkZWZhdWx0QWNjb3VudDogdW5kZWZpbmVkXG59O1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBcbiAqIEBmaWxlIHNoYTMuanNcbiAqIEBhdXRob3IgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE1XG4gKi9cblxudmFyIHV0aWxzID0gcmVxdWlyZSgnLi91dGlscycpO1xudmFyIHNoYTMgPSByZXF1aXJlKCdjcnlwdG8tanMvc2hhMycpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChzdHIsIGlzTmV3KSB7XG4gICAgaWYgKHN0ci5zdWJzdHIoMCwgMikgPT09ICcweCcgJiYgIWlzTmV3KSB7XG4gICAgICAgIGNvbnNvbGUud2FybigncmVxdWlyZW1lbnQgb2YgdXNpbmcgd2ViMy5mcm9tQXNjaWkgYmVmb3JlIHNoYTMgaXMgZGVwcmVjYXRlZCcpO1xuICAgICAgICBjb25zb2xlLndhcm4oJ25ldyB1c2FnZTogXFwnd2ViMy5zaGEzKFwiaGVsbG9cIilcXCcnKTtcbiAgICAgICAgY29uc29sZS53YXJuKCdzZWUgaHR0cHM6Ly9naXRodWIuY29tL2V0aGVyZXVtL3dlYjMuanMvcHVsbC8yMDUnKTtcbiAgICAgICAgY29uc29sZS53YXJuKCdpZiB5b3UgbmVlZCB0byBoYXNoIGhleCB2YWx1ZSwgeW91IGNhbiBkbyBcXCdzaGEzKFwiMHhmZmZcIiwgdHJ1ZSlcXCcnKTtcbiAgICAgICAgc3RyID0gdXRpbHMudG9Bc2NpaShzdHIpO1xuICAgIH1cblxuICAgIHJldHVybiBzaGEzKHN0ciwge1xuICAgICAgICBvdXRwdXRMZW5ndGg6IDI1NlxuICAgIH0pLnRvU3RyaW5nKCk7XG59O1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBcbiAqIEBmaWxlIHV0aWxzLmpzXG4gKiBAYXV0aG9yIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbi8qKlxuICogVXRpbHNcbiAqIFxuICogQG1vZHVsZSB1dGlsc1xuICovXG5cbi8qKlxuICogVXRpbGl0eSBmdW5jdGlvbnNcbiAqIFxuICogQGNsYXNzIFt1dGlsc10gdXRpbHNcbiAqIEBjb25zdHJ1Y3RvclxuICovXG5cbnZhciBCaWdOdW1iZXIgPSByZXF1aXJlKCdiaWdudW1iZXIuanMnKTtcblxudmFyIHVuaXRNYXAgPSB7XG4gICAgJ3dlaSc6ICAgICAgICAgICcxJyxcbiAgICAna3dlaSc6ICAgICAgICAgJzEwMDAnLFxuICAgICdhZGEnOiAgICAgICAgICAnMTAwMCcsXG4gICAgJ2ZlbXRvZXRoZXInOiAgICcxMDAwJyxcbiAgICAnbXdlaSc6ICAgICAgICAgJzEwMDAwMDAnLFxuICAgICdiYWJiYWdlJzogICAgICAnMTAwMDAwMCcsXG4gICAgJ3BpY29ldGhlcic6ICAgICcxMDAwMDAwJyxcbiAgICAnZ3dlaSc6ICAgICAgICAgJzEwMDAwMDAwMDAnLFxuICAgICdzaGFubm9uJzogICAgICAnMTAwMDAwMDAwMCcsXG4gICAgJ25hbm9ldGhlcic6ICAgICcxMDAwMDAwMDAwJyxcbiAgICAnbmFubyc6ICAgICAgICAgJzEwMDAwMDAwMDAnLFxuICAgICdzemFibyc6ICAgICAgICAnMTAwMDAwMDAwMDAwMCcsXG4gICAgJ21pY3JvZXRoZXInOiAgICcxMDAwMDAwMDAwMDAwJyxcbiAgICAnbWljcm8nOiAgICAgICAgJzEwMDAwMDAwMDAwMDAnLFxuICAgICdmaW5uZXknOiAgICAgICAnMTAwMDAwMDAwMDAwMDAwMCcsXG4gICAgJ21pbGxpZXRoZXInOiAgICAnMTAwMDAwMDAwMDAwMDAwMCcsXG4gICAgJ21pbGxpJzogICAgICAgICAnMTAwMDAwMDAwMDAwMDAwMCcsXG4gICAgJ2V0aGVyJzogICAgICAgICcxMDAwMDAwMDAwMDAwMDAwMDAwJyxcbiAgICAna2V0aGVyJzogICAgICAgJzEwMDAwMDAwMDAwMDAwMDAwMDAwMDAnLFxuICAgICdncmFuZCc6ICAgICAgICAnMTAwMDAwMDAwMDAwMDAwMDAwMDAwMCcsXG4gICAgJ2VpbnN0ZWluJzogICAgICcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwJyxcbiAgICAnbWV0aGVyJzogICAgICAgJzEwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAnLFxuICAgICdnZXRoZXInOiAgICAgICAnMTAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMCcsXG4gICAgJ3RldGhlcic6ICAgICAgICcxMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwJ1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIHBhZCBzdHJpbmcgdG8gZXhwZWN0ZWQgbGVuZ3RoXG4gKlxuICogQG1ldGhvZCBwYWRMZWZ0XG4gKiBAcGFyYW0ge1N0cmluZ30gc3RyaW5nIHRvIGJlIHBhZGRlZFxuICogQHBhcmFtIHtOdW1iZXJ9IGNoYXJhY3RlcnMgdGhhdCByZXN1bHQgc3RyaW5nIHNob3VsZCBoYXZlXG4gKiBAcGFyYW0ge1N0cmluZ30gc2lnbiwgYnkgZGVmYXVsdCAwXG4gKiBAcmV0dXJucyB7U3RyaW5nfSByaWdodCBhbGlnbmVkIHN0cmluZ1xuICovXG52YXIgcGFkTGVmdCA9IGZ1bmN0aW9uIChzdHJpbmcsIGNoYXJzLCBzaWduKSB7XG4gICAgcmV0dXJuIG5ldyBBcnJheShjaGFycyAtIHN0cmluZy5sZW5ndGggKyAxKS5qb2luKHNpZ24gPyBzaWduIDogXCIwXCIpICsgc3RyaW5nO1xufTtcblxuLyoqIFxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBnZXQgc3RpbmcgZnJvbSBpdCdzIGhleCByZXByZXNlbnRhdGlvblxuICpcbiAqIEBtZXRob2QgdG9Bc2NpaVxuICogQHBhcmFtIHtTdHJpbmd9IHN0cmluZyBpbiBoZXhcbiAqIEByZXR1cm5zIHtTdHJpbmd9IGFzY2lpIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiBoZXggdmFsdWVcbiAqL1xudmFyIHRvQXNjaWkgPSBmdW5jdGlvbihoZXgpIHtcbi8vIEZpbmQgdGVybWluYXRpb25cbiAgICB2YXIgc3RyID0gXCJcIjtcbiAgICB2YXIgaSA9IDAsIGwgPSBoZXgubGVuZ3RoO1xuICAgIGlmIChoZXguc3Vic3RyaW5nKDAsIDIpID09PSAnMHgnKSB7XG4gICAgICAgIGkgPSAyO1xuICAgIH1cbiAgICBmb3IgKDsgaSA8IGw7IGkrPTIpIHtcbiAgICAgICAgdmFyIGNvZGUgPSBwYXJzZUludChoZXguc3Vic3RyKGksIDIpLCAxNik7XG4gICAgICAgIGlmIChjb2RlID09PSAwKSB7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuXG4gICAgICAgIHN0ciArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGNvZGUpO1xuICAgIH1cblxuICAgIHJldHVybiBzdHI7XG59O1xuICAgIFxuLyoqXG4gKiBTaG9sZCBiZSBjYWxsZWQgdG8gZ2V0IGhleCByZXByZXNlbnRhdGlvbiAocHJlZml4ZWQgYnkgMHgpIG9mIGFzY2lpIHN0cmluZyBcbiAqXG4gKiBAbWV0aG9kIHRvSGV4TmF0aXZlXG4gKiBAcGFyYW0ge1N0cmluZ30gc3RyaW5nXG4gKiBAcmV0dXJucyB7U3RyaW5nfSBoZXggcmVwcmVzZW50YXRpb24gb2YgaW5wdXQgc3RyaW5nXG4gKi9cbnZhciB0b0hleE5hdGl2ZSA9IGZ1bmN0aW9uKHN0cikge1xuICAgIHZhciBoZXggPSBcIlwiO1xuICAgIGZvcih2YXIgaSA9IDA7IGkgPCBzdHIubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIG4gPSBzdHIuY2hhckNvZGVBdChpKS50b1N0cmluZygxNik7XG4gICAgICAgIGhleCArPSBuLmxlbmd0aCA8IDIgPyAnMCcgKyBuIDogbjtcbiAgICB9XG5cbiAgICByZXR1cm4gaGV4O1xufTtcblxuLyoqXG4gKiBTaG9sZCBiZSBjYWxsZWQgdG8gZ2V0IGhleCByZXByZXNlbnRhdGlvbiAocHJlZml4ZWQgYnkgMHgpIG9mIGFzY2lpIHN0cmluZyBcbiAqXG4gKiBAbWV0aG9kIGZyb21Bc2NpaVxuICogQHBhcmFtIHtTdHJpbmd9IHN0cmluZ1xuICogQHBhcmFtIHtOdW1iZXJ9IG9wdGlvbmFsIHBhZGRpbmdcbiAqIEByZXR1cm5zIHtTdHJpbmd9IGhleCByZXByZXNlbnRhdGlvbiBvZiBpbnB1dCBzdHJpbmdcbiAqL1xudmFyIGZyb21Bc2NpaSA9IGZ1bmN0aW9uKHN0ciwgcGFkKSB7XG4gICAgcGFkID0gcGFkID09PSB1bmRlZmluZWQgPyAwIDogcGFkO1xuICAgIHZhciBoZXggPSB0b0hleE5hdGl2ZShzdHIpO1xuICAgIHdoaWxlIChoZXgubGVuZ3RoIDwgcGFkKjIpXG4gICAgICAgIGhleCArPSBcIjAwXCI7XG4gICAgcmV0dXJuIFwiMHhcIiArIGhleDtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gY3JlYXRlIGZ1bGwgZnVuY3Rpb24vZXZlbnQgbmFtZSBmcm9tIGpzb24gYWJpXG4gKlxuICogQG1ldGhvZCB0cmFuc2Zvcm1Ub0Z1bGxOYW1lXG4gKiBAcGFyYW0ge09iamVjdH0ganNvbi1hYmlcbiAqIEByZXR1cm4ge1N0cmluZ30gZnVsbCBmbmN0aW9uL2V2ZW50IG5hbWVcbiAqL1xudmFyIHRyYW5zZm9ybVRvRnVsbE5hbWUgPSBmdW5jdGlvbiAoanNvbikge1xuICAgIGlmIChqc29uLm5hbWUuaW5kZXhPZignKCcpICE9PSAtMSkge1xuICAgICAgICByZXR1cm4ganNvbi5uYW1lO1xuICAgIH1cblxuICAgIHZhciB0eXBlTmFtZSA9IGpzb24uaW5wdXRzLm1hcChmdW5jdGlvbihpKXtyZXR1cm4gaS50eXBlOyB9KS5qb2luKCk7XG4gICAgcmV0dXJuIGpzb24ubmFtZSArICcoJyArIHR5cGVOYW1lICsgJyknO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGdldCBkaXNwbGF5IG5hbWUgb2YgY29udHJhY3QgZnVuY3Rpb25cbiAqIFxuICogQG1ldGhvZCBleHRyYWN0RGlzcGxheU5hbWVcbiAqIEBwYXJhbSB7U3RyaW5nfSBuYW1lIG9mIGZ1bmN0aW9uL2V2ZW50XG4gKiBAcmV0dXJucyB7U3RyaW5nfSBkaXNwbGF5IG5hbWUgZm9yIGZ1bmN0aW9uL2V2ZW50IGVnLiBtdWx0aXBseSh1aW50MjU2KSAtPiBtdWx0aXBseVxuICovXG52YXIgZXh0cmFjdERpc3BsYXlOYW1lID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgICB2YXIgbGVuZ3RoID0gbmFtZS5pbmRleE9mKCcoJyk7IFxuICAgIHJldHVybiBsZW5ndGggIT09IC0xID8gbmFtZS5zdWJzdHIoMCwgbGVuZ3RoKSA6IG5hbWU7XG59O1xuXG4vLy8gQHJldHVybnMgb3ZlcmxvYWRlZCBwYXJ0IG9mIGZ1bmN0aW9uL2V2ZW50IG5hbWVcbnZhciBleHRyYWN0VHlwZU5hbWUgPSBmdW5jdGlvbiAobmFtZSkge1xuICAgIC8vLyBUT0RPOiBtYWtlIGl0IGludnVsbmVyYWJsZVxuICAgIHZhciBsZW5ndGggPSBuYW1lLmluZGV4T2YoJygnKTtcbiAgICByZXR1cm4gbGVuZ3RoICE9PSAtMSA/IG5hbWUuc3Vic3RyKGxlbmd0aCArIDEsIG5hbWUubGVuZ3RoIC0gMSAtIChsZW5ndGggKyAxKSkucmVwbGFjZSgnICcsICcnKSA6IFwiXCI7XG59O1xuXG4vKipcbiAqIENvbnZlcnRzIHZhbHVlIHRvIGl0J3MgZGVjaW1hbCByZXByZXNlbnRhdGlvbiBpbiBzdHJpbmdcbiAqXG4gKiBAbWV0aG9kIHRvRGVjaW1hbFxuICogQHBhcmFtIHtTdHJpbmd8TnVtYmVyfEJpZ051bWJlcn1cbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xudmFyIHRvRGVjaW1hbCA9IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgIHJldHVybiB0b0JpZ051bWJlcih2YWx1ZSkudG9OdW1iZXIoKTtcbn07XG5cbi8qKlxuICogQ29udmVydHMgdmFsdWUgdG8gaXQncyBoZXggcmVwcmVzZW50YXRpb25cbiAqXG4gKiBAbWV0aG9kIGZyb21EZWNpbWFsXG4gKiBAcGFyYW0ge1N0cmluZ3xOdW1iZXJ8QmlnTnVtYmVyfVxuICogQHJldHVybiB7U3RyaW5nfVxuICovXG52YXIgZnJvbURlY2ltYWwgPSBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICB2YXIgbnVtYmVyID0gdG9CaWdOdW1iZXIodmFsdWUpO1xuICAgIHZhciByZXN1bHQgPSBudW1iZXIudG9TdHJpbmcoMTYpO1xuXG4gICAgcmV0dXJuIG51bWJlci5sZXNzVGhhbigwKSA/ICctMHgnICsgcmVzdWx0LnN1YnN0cigxKSA6ICcweCcgKyByZXN1bHQ7XG59O1xuXG4vKipcbiAqIEF1dG8gY29udmVydHMgYW55IGdpdmVuIHZhbHVlIGludG8gaXQncyBoZXggcmVwcmVzZW50YXRpb24uXG4gKlxuICogQW5kIGV2ZW4gc3RyaW5naWZ5cyBvYmplY3RzIGJlZm9yZS5cbiAqXG4gKiBAbWV0aG9kIHRvSGV4XG4gKiBAcGFyYW0ge1N0cmluZ3xOdW1iZXJ8QmlnTnVtYmVyfE9iamVjdH1cbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xudmFyIHRvSGV4ID0gZnVuY3Rpb24gKHZhbCkge1xuICAgIC8qanNoaW50IG1heGNvbXBsZXhpdHk6NyAqL1xuXG4gICAgaWYgKGlzQm9vbGVhbih2YWwpKVxuICAgICAgICByZXR1cm4gZnJvbURlY2ltYWwoK3ZhbCk7XG5cbiAgICBpZiAoaXNCaWdOdW1iZXIodmFsKSlcbiAgICAgICAgcmV0dXJuIGZyb21EZWNpbWFsKHZhbCk7XG5cbiAgICBpZiAoaXNPYmplY3QodmFsKSlcbiAgICAgICAgcmV0dXJuIGZyb21Bc2NpaShKU09OLnN0cmluZ2lmeSh2YWwpKTtcblxuICAgIC8vIGlmIGl0cyBhIG5lZ2F0aXZlIG51bWJlciwgcGFzcyBpdCB0aHJvdWdoIGZyb21EZWNpbWFsXG4gICAgaWYgKGlzU3RyaW5nKHZhbCkpIHtcbiAgICAgICAgaWYgKHZhbC5pbmRleE9mKCctMHgnKSA9PT0gMClcbiAgICAgICAgICAgcmV0dXJuIGZyb21EZWNpbWFsKHZhbCk7XG4gICAgICAgIGVsc2UgaWYgKCFpc0Zpbml0ZSh2YWwpKVxuICAgICAgICAgICAgcmV0dXJuIGZyb21Bc2NpaSh2YWwpO1xuICAgIH1cblxuICAgIHJldHVybiBmcm9tRGVjaW1hbCh2YWwpO1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIHZhbHVlIG9mIHVuaXQgaW4gV2VpXG4gKlxuICogQG1ldGhvZCBnZXRWYWx1ZU9mVW5pdFxuICogQHBhcmFtIHtTdHJpbmd9IHVuaXQgdGhlIHVuaXQgdG8gY29udmVydCB0bywgZGVmYXVsdCBldGhlclxuICogQHJldHVybnMge0JpZ051bWJlcn0gdmFsdWUgb2YgdGhlIHVuaXQgKGluIFdlaSlcbiAqIEB0aHJvd3MgZXJyb3IgaWYgdGhlIHVuaXQgaXMgbm90IGNvcnJlY3Q6d1xuICovXG52YXIgZ2V0VmFsdWVPZlVuaXQgPSBmdW5jdGlvbiAodW5pdCkge1xuICAgIHVuaXQgPSB1bml0ID8gdW5pdC50b0xvd2VyQ2FzZSgpIDogJ2V0aGVyJztcbiAgICB2YXIgdW5pdFZhbHVlID0gdW5pdE1hcFt1bml0XTtcbiAgICBpZiAodW5pdFZhbHVlID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdUaGlzIHVuaXQgZG9lc25cXCd0IGV4aXN0cywgcGxlYXNlIHVzZSB0aGUgb25lIG9mIHRoZSBmb2xsb3dpbmcgdW5pdHMnICsgSlNPTi5zdHJpbmdpZnkodW5pdE1hcCwgbnVsbCwgMikpO1xuICAgIH1cbiAgICByZXR1cm4gbmV3IEJpZ051bWJlcih1bml0VmFsdWUsIDEwKTtcbn07XG5cbi8qKlxuICogVGFrZXMgYSBudW1iZXIgb2Ygd2VpIGFuZCBjb252ZXJ0cyBpdCB0byBhbnkgb3RoZXIgZXRoZXIgdW5pdC5cbiAqXG4gKiBQb3NzaWJsZSB1bml0cyBhcmU6XG4gKiAgIFNJIFNob3J0ICAgU0kgRnVsbCAgICAgICAgRWZmaWd5ICAgICAgIE90aGVyXG4gKiAtIGt3ZWkgICAgICAgZmVtdG9ldGhlciAgICAgYWRhXG4gKiAtIG13ZWkgICAgICAgcGljb2V0aGVyICAgICAgYmFiYmFnZVxuICogLSBnd2VpICAgICAgIG5hbm9ldGhlciAgICAgIHNoYW5ub24gICAgICBuYW5vXG4gKiAtIC0tICAgICAgICAgbWljcm9ldGhlciAgICAgc3phYm8gICAgICAgIG1pY3JvXG4gKiAtIC0tICAgICAgICAgbWlsbGlldGhlciAgICAgZmlubmV5ICAgICAgIG1pbGxpXG4gKiAtIGV0aGVyICAgICAgLS0gICAgICAgICAgICAgLS1cbiAqIC0ga2V0aGVyICAgICAgICAgICAgICAgICAgICBlaW5zdGVpbiAgICAgZ3JhbmQgXG4gKiAtIG1ldGhlclxuICogLSBnZXRoZXJcbiAqIC0gdGV0aGVyXG4gKlxuICogQG1ldGhvZCBmcm9tV2VpXG4gKiBAcGFyYW0ge051bWJlcnxTdHJpbmd9IG51bWJlciBjYW4gYmUgYSBudW1iZXIsIG51bWJlciBzdHJpbmcgb3IgYSBIRVggb2YgYSBkZWNpbWFsXG4gKiBAcGFyYW0ge1N0cmluZ30gdW5pdCB0aGUgdW5pdCB0byBjb252ZXJ0IHRvLCBkZWZhdWx0IGV0aGVyXG4gKiBAcmV0dXJuIHtTdHJpbmd8T2JqZWN0fSBXaGVuIGdpdmVuIGEgQmlnTnVtYmVyIG9iamVjdCBpdCByZXR1cm5zIG9uZSBhcyB3ZWxsLCBvdGhlcndpc2UgYSBudW1iZXJcbiovXG52YXIgZnJvbVdlaSA9IGZ1bmN0aW9uKG51bWJlciwgdW5pdCkge1xuICAgIHZhciByZXR1cm5WYWx1ZSA9IHRvQmlnTnVtYmVyKG51bWJlcikuZGl2aWRlZEJ5KGdldFZhbHVlT2ZVbml0KHVuaXQpKTtcblxuICAgIHJldHVybiBpc0JpZ051bWJlcihudW1iZXIpID8gcmV0dXJuVmFsdWUgOiByZXR1cm5WYWx1ZS50b1N0cmluZygxMCk7IFxufTtcblxuLyoqXG4gKiBUYWtlcyBhIG51bWJlciBvZiBhIHVuaXQgYW5kIGNvbnZlcnRzIGl0IHRvIHdlaS5cbiAqXG4gKiBQb3NzaWJsZSB1bml0cyBhcmU6XG4gKiAgIFNJIFNob3J0ICAgU0kgRnVsbCAgICAgICAgRWZmaWd5ICAgICAgIE90aGVyXG4gKiAtIGt3ZWkgICAgICAgZmVtdG9ldGhlciAgICAgYWRhXG4gKiAtIG13ZWkgICAgICAgcGljb2V0aGVyICAgICAgYmFiYmFnZSAgICAgICBcbiAqIC0gZ3dlaSAgICAgICBuYW5vZXRoZXIgICAgICBzaGFubm9uICAgICAgbmFub1xuICogLSAtLSAgICAgICAgIG1pY3JvZXRoZXIgICAgIHN6YWJvICAgICAgICBtaWNyb1xuICogLSAtLSAgICAgICAgIG1pbGxpZXRoZXIgICAgIGZpbm5leSAgICAgICBtaWxsaVxuICogLSBldGhlciAgICAgIC0tICAgICAgICAgICAgIC0tXG4gKiAtIGtldGhlciAgICAgICAgICAgICAgICAgICAgZWluc3RlaW4gICAgIGdyYW5kIFxuICogLSBtZXRoZXJcbiAqIC0gZ2V0aGVyXG4gKiAtIHRldGhlclxuICpcbiAqIEBtZXRob2QgdG9XZWlcbiAqIEBwYXJhbSB7TnVtYmVyfFN0cmluZ3xCaWdOdW1iZXJ9IG51bWJlciBjYW4gYmUgYSBudW1iZXIsIG51bWJlciBzdHJpbmcgb3IgYSBIRVggb2YgYSBkZWNpbWFsXG4gKiBAcGFyYW0ge1N0cmluZ30gdW5pdCB0aGUgdW5pdCB0byBjb252ZXJ0IGZyb20sIGRlZmF1bHQgZXRoZXJcbiAqIEByZXR1cm4ge1N0cmluZ3xPYmplY3R9IFdoZW4gZ2l2ZW4gYSBCaWdOdW1iZXIgb2JqZWN0IGl0IHJldHVybnMgb25lIGFzIHdlbGwsIG90aGVyd2lzZSBhIG51bWJlclxuKi9cbnZhciB0b1dlaSA9IGZ1bmN0aW9uKG51bWJlciwgdW5pdCkge1xuICAgIHZhciByZXR1cm5WYWx1ZSA9IHRvQmlnTnVtYmVyKG51bWJlcikudGltZXMoZ2V0VmFsdWVPZlVuaXQodW5pdCkpO1xuXG4gICAgcmV0dXJuIGlzQmlnTnVtYmVyKG51bWJlcikgPyByZXR1cm5WYWx1ZSA6IHJldHVyblZhbHVlLnRvU3RyaW5nKDEwKTsgXG59O1xuXG4vKipcbiAqIFRha2VzIGFuIGlucHV0IGFuZCB0cmFuc2Zvcm1zIGl0IGludG8gYW4gYmlnbnVtYmVyXG4gKlxuICogQG1ldGhvZCB0b0JpZ051bWJlclxuICogQHBhcmFtIHtOdW1iZXJ8U3RyaW5nfEJpZ051bWJlcn0gYSBudW1iZXIsIHN0cmluZywgSEVYIHN0cmluZyBvciBCaWdOdW1iZXJcbiAqIEByZXR1cm4ge0JpZ051bWJlcn0gQmlnTnVtYmVyXG4qL1xudmFyIHRvQmlnTnVtYmVyID0gZnVuY3Rpb24obnVtYmVyKSB7XG4gICAgLypqc2hpbnQgbWF4Y29tcGxleGl0eTo1ICovXG4gICAgbnVtYmVyID0gbnVtYmVyIHx8IDA7XG4gICAgaWYgKGlzQmlnTnVtYmVyKG51bWJlcikpXG4gICAgICAgIHJldHVybiBudW1iZXI7XG5cbiAgICBpZiAoaXNTdHJpbmcobnVtYmVyKSAmJiAobnVtYmVyLmluZGV4T2YoJzB4JykgPT09IDAgfHwgbnVtYmVyLmluZGV4T2YoJy0weCcpID09PSAwKSkge1xuICAgICAgICByZXR1cm4gbmV3IEJpZ051bWJlcihudW1iZXIucmVwbGFjZSgnMHgnLCcnKSwgMTYpO1xuICAgIH1cbiAgIFxuICAgIHJldHVybiBuZXcgQmlnTnVtYmVyKG51bWJlci50b1N0cmluZygxMCksIDEwKTtcbn07XG5cbi8qKlxuICogVGFrZXMgYW5kIGlucHV0IHRyYW5zZm9ybXMgaXQgaW50byBiaWdudW1iZXIgYW5kIGlmIGl0IGlzIG5lZ2F0aXZlIHZhbHVlLCBpbnRvIHR3bydzIGNvbXBsZW1lbnRcbiAqXG4gKiBAbWV0aG9kIHRvVHdvc0NvbXBsZW1lbnRcbiAqIEBwYXJhbSB7TnVtYmVyfFN0cmluZ3xCaWdOdW1iZXJ9XG4gKiBAcmV0dXJuIHtCaWdOdW1iZXJ9XG4gKi9cbnZhciB0b1R3b3NDb21wbGVtZW50ID0gZnVuY3Rpb24gKG51bWJlcikge1xuICAgIHZhciBiaWdOdW1iZXIgPSB0b0JpZ051bWJlcihudW1iZXIpO1xuICAgIGlmIChiaWdOdW1iZXIubGVzc1RoYW4oMCkpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBCaWdOdW1iZXIoXCJmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmXCIsIDE2KS5wbHVzKGJpZ051bWJlcikucGx1cygxKTtcbiAgICB9XG4gICAgcmV0dXJuIGJpZ051bWJlcjtcbn07XG5cbi8qKlxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBzdHJpbmcgaXMgc3RyaWN0bHkgYW4gYWRkcmVzc1xuICpcbiAqIEBtZXRob2QgaXNTdHJpY3RBZGRyZXNzXG4gKiBAcGFyYW0ge1N0cmluZ30gYWRkcmVzcyB0aGUgZ2l2ZW4gSEVYIGFkcmVzc1xuICogQHJldHVybiB7Qm9vbGVhbn1cbiovXG52YXIgaXNTdHJpY3RBZGRyZXNzID0gZnVuY3Rpb24gKGFkZHJlc3MpIHtcbiAgICByZXR1cm4gL14weFswLTlhLWZdezQwfSQvLnRlc3QoYWRkcmVzcyk7XG59O1xuXG4vKipcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gc3RyaW5nIGlzIGFuIGFkZHJlc3NcbiAqXG4gKiBAbWV0aG9kIGlzQWRkcmVzc1xuICogQHBhcmFtIHtTdHJpbmd9IGFkZHJlc3MgdGhlIGdpdmVuIEhFWCBhZHJlc3NcbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4qL1xudmFyIGlzQWRkcmVzcyA9IGZ1bmN0aW9uIChhZGRyZXNzKSB7XG4gICAgcmV0dXJuIC9eKDB4KT9bMC05YS1mXXs0MH0kLy50ZXN0KGFkZHJlc3MpO1xufTtcblxuLyoqXG4gKiBUcmFuc2Zvcm1zIGdpdmVuIHN0cmluZyB0byB2YWxpZCAyMCBieXRlcy1sZW5ndGggYWRkcmVzIHdpdGggMHggcHJlZml4XG4gKlxuICogQG1ldGhvZCB0b0FkZHJlc3NcbiAqIEBwYXJhbSB7U3RyaW5nfSBhZGRyZXNzXG4gKiBAcmV0dXJuIHtTdHJpbmd9IGZvcm1hdHRlZCBhZGRyZXNzXG4gKi9cbnZhciB0b0FkZHJlc3MgPSBmdW5jdGlvbiAoYWRkcmVzcykge1xuICAgIGlmIChpc1N0cmljdEFkZHJlc3MoYWRkcmVzcykpIHtcbiAgICAgICAgcmV0dXJuIGFkZHJlc3M7XG4gICAgfVxuICAgIFxuICAgIGlmICgvXlswLTlhLWZdezQwfSQvLnRlc3QoYWRkcmVzcykpIHtcbiAgICAgICAgcmV0dXJuICcweCcgKyBhZGRyZXNzO1xuICAgIH1cblxuICAgIHJldHVybiAnMHgnICsgcGFkTGVmdCh0b0hleChhZGRyZXNzKS5zdWJzdHIoMiksIDQwKTtcbn07XG5cblxuLyoqXG4gKiBSZXR1cm5zIHRydWUgaWYgb2JqZWN0IGlzIEJpZ051bWJlciwgb3RoZXJ3aXNlIGZhbHNlXG4gKlxuICogQG1ldGhvZCBpc0JpZ051bWJlclxuICogQHBhcmFtIHtPYmplY3R9XG4gKiBAcmV0dXJuIHtCb29sZWFufSBcbiAqL1xudmFyIGlzQmlnTnVtYmVyID0gZnVuY3Rpb24gKG9iamVjdCkge1xuICAgIHJldHVybiBvYmplY3QgaW5zdGFuY2VvZiBCaWdOdW1iZXIgfHxcbiAgICAgICAgKG9iamVjdCAmJiBvYmplY3QuY29uc3RydWN0b3IgJiYgb2JqZWN0LmNvbnN0cnVjdG9yLm5hbWUgPT09ICdCaWdOdW1iZXInKTtcbn07XG5cbi8qKlxuICogUmV0dXJucyB0cnVlIGlmIG9iamVjdCBpcyBzdHJpbmcsIG90aGVyd2lzZSBmYWxzZVxuICogXG4gKiBAbWV0aG9kIGlzU3RyaW5nXG4gKiBAcGFyYW0ge09iamVjdH1cbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbnZhciBpc1N0cmluZyA9IGZ1bmN0aW9uIChvYmplY3QpIHtcbiAgICByZXR1cm4gdHlwZW9mIG9iamVjdCA9PT0gJ3N0cmluZycgfHxcbiAgICAgICAgKG9iamVjdCAmJiBvYmplY3QuY29uc3RydWN0b3IgJiYgb2JqZWN0LmNvbnN0cnVjdG9yLm5hbWUgPT09ICdTdHJpbmcnKTtcbn07XG5cbi8qKlxuICogUmV0dXJucyB0cnVlIGlmIG9iamVjdCBpcyBmdW5jdGlvbiwgb3RoZXJ3aXNlIGZhbHNlXG4gKlxuICogQG1ldGhvZCBpc0Z1bmN0aW9uXG4gKiBAcGFyYW0ge09iamVjdH1cbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbnZhciBpc0Z1bmN0aW9uID0gZnVuY3Rpb24gKG9iamVjdCkge1xuICAgIHJldHVybiB0eXBlb2Ygb2JqZWN0ID09PSAnZnVuY3Rpb24nO1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIHRydWUgaWYgb2JqZWN0IGlzIE9iamV0LCBvdGhlcndpc2UgZmFsc2VcbiAqXG4gKiBAbWV0aG9kIGlzT2JqZWN0XG4gKiBAcGFyYW0ge09iamVjdH1cbiAqIEByZXR1cm4ge0Jvb2xlYW59XG4gKi9cbnZhciBpc09iamVjdCA9IGZ1bmN0aW9uIChvYmplY3QpIHtcbiAgICByZXR1cm4gdHlwZW9mIG9iamVjdCA9PT0gJ29iamVjdCc7XG59O1xuXG4vKipcbiAqIFJldHVybnMgdHJ1ZSBpZiBvYmplY3QgaXMgYm9vbGVhbiwgb3RoZXJ3aXNlIGZhbHNlXG4gKlxuICogQG1ldGhvZCBpc0Jvb2xlYW5cbiAqIEBwYXJhbSB7T2JqZWN0fVxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqL1xudmFyIGlzQm9vbGVhbiA9IGZ1bmN0aW9uIChvYmplY3QpIHtcbiAgICByZXR1cm4gdHlwZW9mIG9iamVjdCA9PT0gJ2Jvb2xlYW4nO1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIHRydWUgaWYgb2JqZWN0IGlzIGFycmF5LCBvdGhlcndpc2UgZmFsc2VcbiAqXG4gKiBAbWV0aG9kIGlzQXJyYXlcbiAqIEBwYXJhbSB7T2JqZWN0fVxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqL1xudmFyIGlzQXJyYXkgPSBmdW5jdGlvbiAob2JqZWN0KSB7XG4gICAgcmV0dXJuIG9iamVjdCBpbnN0YW5jZW9mIEFycmF5OyBcbn07XG5cbi8qKlxuICogUmV0dXJucyB0cnVlIGlmIGdpdmVuIHN0cmluZyBpcyB2YWxpZCBqc29uIG9iamVjdFxuICogXG4gKiBAbWV0aG9kIGlzSnNvblxuICogQHBhcmFtIHtTdHJpbmd9XG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG52YXIgaXNKc29uID0gZnVuY3Rpb24gKHN0cikge1xuICAgIHRyeSB7XG4gICAgICAgIHJldHVybiAhIUpTT04ucGFyc2Uoc3RyKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG59O1xuXG4vKipcbiAqIFRoaXMgbWV0aG9kIHNob3VsZCBiZSBjYWxsZWQgdG8gY2hlY2sgaWYgc3RyaW5nIGlzIHZhbGlkIGV0aGVyZXVtIElCQU4gbnVtYmVyXG4gKiBTdXBwb3J0cyBkaXJlY3QgYW5kIGluZGlyZWN0IElCQU5zXG4gKlxuICogQG1ldGhvZCBpc0lCQU5cbiAqIEBwYXJhbSB7U3RyaW5nfVxuICogQHJldHVybiB7Qm9vbGVhbn1cbiAqL1xudmFyIGlzSUJBTiA9IGZ1bmN0aW9uIChpYmFuKSB7XG4gICAgcmV0dXJuIC9eWEVbMC05XXsyfShFVEhbMC05QS1aXXsxM318WzAtOUEtWl17MzB9KSQvLnRlc3QoaWJhbik7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBwYWRMZWZ0OiBwYWRMZWZ0LFxuICAgIHRvSGV4OiB0b0hleCxcbiAgICB0b0RlY2ltYWw6IHRvRGVjaW1hbCxcbiAgICBmcm9tRGVjaW1hbDogZnJvbURlY2ltYWwsXG4gICAgdG9Bc2NpaTogdG9Bc2NpaSxcbiAgICBmcm9tQXNjaWk6IGZyb21Bc2NpaSxcbiAgICB0cmFuc2Zvcm1Ub0Z1bGxOYW1lOiB0cmFuc2Zvcm1Ub0Z1bGxOYW1lLFxuICAgIGV4dHJhY3REaXNwbGF5TmFtZTogZXh0cmFjdERpc3BsYXlOYW1lLFxuICAgIGV4dHJhY3RUeXBlTmFtZTogZXh0cmFjdFR5cGVOYW1lLFxuICAgIHRvV2VpOiB0b1dlaSxcbiAgICBmcm9tV2VpOiBmcm9tV2VpLFxuICAgIHRvQmlnTnVtYmVyOiB0b0JpZ051bWJlcixcbiAgICB0b1R3b3NDb21wbGVtZW50OiB0b1R3b3NDb21wbGVtZW50LFxuICAgIHRvQWRkcmVzczogdG9BZGRyZXNzLFxuICAgIGlzQmlnTnVtYmVyOiBpc0JpZ051bWJlcixcbiAgICBpc1N0cmljdEFkZHJlc3M6IGlzU3RyaWN0QWRkcmVzcyxcbiAgICBpc0FkZHJlc3M6IGlzQWRkcmVzcyxcbiAgICBpc0Z1bmN0aW9uOiBpc0Z1bmN0aW9uLFxuICAgIGlzU3RyaW5nOiBpc1N0cmluZyxcbiAgICBpc09iamVjdDogaXNPYmplY3QsXG4gICAgaXNCb29sZWFuOiBpc0Jvb2xlYW4sXG4gICAgaXNBcnJheTogaXNBcnJheSxcbiAgICBpc0pzb246IGlzSnNvbixcbiAgICBpc0lCQU46IGlzSUJBTlxufTtcblxuIiwibW9kdWxlLmV4cG9ydHM9e1xuICAgIFwidmVyc2lvblwiOiBcIjAuNS4wXCJcbn1cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqIEBmaWxlIHdlYjMuanNcbiAqIEBhdXRob3JzOlxuICogICBKZWZmcmV5IFdpbGNrZSA8amVmZkBldGhkZXYuY29tPlxuICogICBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqICAgTWFyaWFuIE9hbmNlYSA8bWFyaWFuQGV0aGRldi5jb20+XG4gKiAgIEZhYmlhbiBWb2dlbHN0ZWxsZXIgPGZhYmlhbkBldGhkZXYuY29tPlxuICogICBHYXYgV29vZCA8Z0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNFxuICovXG5cbnZhciB2ZXJzaW9uID0gcmVxdWlyZSgnLi92ZXJzaW9uLmpzb24nKTtcbnZhciBuZXQgPSByZXF1aXJlKCcuL3dlYjMvbmV0Jyk7XG52YXIgZXRoID0gcmVxdWlyZSgnLi93ZWIzL2V0aCcpO1xudmFyIGRiID0gcmVxdWlyZSgnLi93ZWIzL2RiJyk7XG52YXIgc2hoID0gcmVxdWlyZSgnLi93ZWIzL3NoaCcpO1xudmFyIHdhdGNoZXMgPSByZXF1aXJlKCcuL3dlYjMvd2F0Y2hlcycpO1xudmFyIEZpbHRlciA9IHJlcXVpcmUoJy4vd2ViMy9maWx0ZXInKTtcbnZhciB1dGlscyA9IHJlcXVpcmUoJy4vdXRpbHMvdXRpbHMnKTtcbnZhciBmb3JtYXR0ZXJzID0gcmVxdWlyZSgnLi93ZWIzL2Zvcm1hdHRlcnMnKTtcbnZhciBSZXF1ZXN0TWFuYWdlciA9IHJlcXVpcmUoJy4vd2ViMy9yZXF1ZXN0bWFuYWdlcicpO1xudmFyIE1ldGhvZCA9IHJlcXVpcmUoJy4vd2ViMy9tZXRob2QnKTtcbnZhciBjID0gcmVxdWlyZSgnLi91dGlscy9jb25maWcnKTtcbnZhciBQcm9wZXJ0eSA9IHJlcXVpcmUoJy4vd2ViMy9wcm9wZXJ0eScpO1xudmFyIEJhdGNoID0gcmVxdWlyZSgnLi93ZWIzL2JhdGNoJyk7XG52YXIgc2hhMyA9IHJlcXVpcmUoJy4vdXRpbHMvc2hhMycpO1xuXG52YXIgd2ViM1Byb3BlcnRpZXMgPSBbXG4gICAgbmV3IFByb3BlcnR5KHtcbiAgICAgICAgbmFtZTogJ3ZlcnNpb24uY2xpZW50JyxcbiAgICAgICAgZ2V0dGVyOiAnd2ViM19jbGllbnRWZXJzaW9uJ1xuICAgIH0pLFxuICAgIG5ldyBQcm9wZXJ0eSh7XG4gICAgICAgIG5hbWU6ICd2ZXJzaW9uLm5ldHdvcmsnLFxuICAgICAgICBnZXR0ZXI6ICduZXRfdmVyc2lvbicsXG4gICAgICAgIGlucHV0Rm9ybWF0dGVyOiB1dGlscy50b0RlY2ltYWxcbiAgICB9KSxcbiAgICBuZXcgUHJvcGVydHkoe1xuICAgICAgICBuYW1lOiAndmVyc2lvbi5ldGhlcmV1bScsXG4gICAgICAgIGdldHRlcjogJ2V0aF9wcm90b2NvbFZlcnNpb24nLFxuICAgICAgICBpbnB1dEZvcm1hdHRlcjogdXRpbHMudG9EZWNpbWFsXG4gICAgfSksXG4gICAgbmV3IFByb3BlcnR5KHtcbiAgICAgICAgbmFtZTogJ3ZlcnNpb24ud2hpc3BlcicsXG4gICAgICAgIGdldHRlcjogJ3NoaF92ZXJzaW9uJyxcbiAgICAgICAgaW5wdXRGb3JtYXR0ZXI6IHV0aWxzLnRvRGVjaW1hbFxuICAgIH0pXG5dO1xuXG4vLy8gY3JlYXRlcyBtZXRob2RzIGluIGEgZ2l2ZW4gb2JqZWN0IGJhc2VkIG9uIG1ldGhvZCBkZXNjcmlwdGlvbiBvbiBpbnB1dFxuLy8vIHNldHVwcyBhcGkgY2FsbHMgZm9yIHRoZXNlIG1ldGhvZHNcbnZhciBzZXR1cE1ldGhvZHMgPSBmdW5jdGlvbiAob2JqLCBtZXRob2RzKSB7XG4gICAgbWV0aG9kcy5mb3JFYWNoKGZ1bmN0aW9uIChtZXRob2QpIHtcbiAgICAgICAgbWV0aG9kLmF0dGFjaFRvT2JqZWN0KG9iaik7XG4gICAgfSk7XG59O1xuXG4vLy8gY3JlYXRlcyBwcm9wZXJ0aWVzIGluIGEgZ2l2ZW4gb2JqZWN0IGJhc2VkIG9uIHByb3BlcnRpZXMgZGVzY3JpcHRpb24gb24gaW5wdXRcbi8vLyBzZXR1cHMgYXBpIGNhbGxzIGZvciB0aGVzZSBwcm9wZXJ0aWVzXG52YXIgc2V0dXBQcm9wZXJ0aWVzID0gZnVuY3Rpb24gKG9iaiwgcHJvcGVydGllcykge1xuICAgIHByb3BlcnRpZXMuZm9yRWFjaChmdW5jdGlvbiAocHJvcGVydHkpIHtcbiAgICAgICAgcHJvcGVydHkuYXR0YWNoVG9PYmplY3Qob2JqKTtcbiAgICB9KTtcbn07XG5cbi8vLyBzZXR1cHMgd2ViMyBvYmplY3QsIGFuZCBpdCdzIGluLWJyb3dzZXIgZXhlY3V0ZWQgbWV0aG9kc1xudmFyIHdlYjMgPSB7fTtcbndlYjMucHJvdmlkZXJzID0ge307XG53ZWIzLnZlcnNpb24gPSB7fTtcbndlYjMudmVyc2lvbi5hcGkgPSB2ZXJzaW9uLnZlcnNpb247XG53ZWIzLmV0aCA9IHt9O1xuXG4vKmpzaGludCBtYXhwYXJhbXM6NCAqL1xud2ViMy5ldGguZmlsdGVyID0gZnVuY3Rpb24gKGZpbCwgZXZlbnRQYXJhbXMsIG9wdGlvbnMsIGZvcm1hdHRlcikge1xuXG4gICAgLy8gaWYgaXRzIGV2ZW50LCB0cmVhdCBpdCBkaWZmZXJlbnRseVxuICAgIC8vIFRPRE86IHNpbXBsaWZ5IGFuZCByZW1vdmVcbiAgICBpZiAoZmlsLl9pc0V2ZW50KSB7XG4gICAgICAgIHJldHVybiBmaWwoZXZlbnRQYXJhbXMsIG9wdGlvbnMpO1xuICAgIH1cblxuICAgIC8vIHdoYXQgb3V0cHV0TG9nRm9ybWF0dGVyPyB0aGF0J3Mgd3JvbmdcbiAgICAvL3JldHVybiBuZXcgRmlsdGVyKGZpbCwgd2F0Y2hlcy5ldGgoKSwgZm9ybWF0dGVycy5vdXRwdXRMb2dGb3JtYXR0ZXIpO1xuICAgIHJldHVybiBuZXcgRmlsdGVyKGZpbCwgd2F0Y2hlcy5ldGgoKSwgZm9ybWF0dGVyIHx8IGZvcm1hdHRlcnMub3V0cHV0TG9nRm9ybWF0dGVyKTtcbn07XG4vKmpzaGludCBtYXhwYXJhbXM6MyAqL1xuXG53ZWIzLnNoaCA9IHt9O1xud2ViMy5zaGguZmlsdGVyID0gZnVuY3Rpb24gKGZpbCkge1xuICAgIHJldHVybiBuZXcgRmlsdGVyKGZpbCwgd2F0Y2hlcy5zaGgoKSwgZm9ybWF0dGVycy5vdXRwdXRQb3N0Rm9ybWF0dGVyKTtcbn07XG53ZWIzLm5ldCA9IHt9O1xud2ViMy5kYiA9IHt9O1xud2ViMy5zZXRQcm92aWRlciA9IGZ1bmN0aW9uIChwcm92aWRlcikge1xuICAgIFJlcXVlc3RNYW5hZ2VyLmdldEluc3RhbmNlKCkuc2V0UHJvdmlkZXIocHJvdmlkZXIpO1xufTtcbndlYjMucmVzZXQgPSBmdW5jdGlvbiAoKSB7XG4gICAgUmVxdWVzdE1hbmFnZXIuZ2V0SW5zdGFuY2UoKS5yZXNldCgpO1xuICAgIGMuZGVmYXVsdEJsb2NrID0gJ2xhdGVzdCc7XG4gICAgYy5kZWZhdWx0QWNjb3VudCA9IHVuZGVmaW5lZDtcbn07XG53ZWIzLnRvSGV4ID0gdXRpbHMudG9IZXg7XG53ZWIzLnRvQXNjaWkgPSB1dGlscy50b0FzY2lpO1xud2ViMy5mcm9tQXNjaWkgPSB1dGlscy5mcm9tQXNjaWk7XG53ZWIzLnRvRGVjaW1hbCA9IHV0aWxzLnRvRGVjaW1hbDtcbndlYjMuZnJvbURlY2ltYWwgPSB1dGlscy5mcm9tRGVjaW1hbDtcbndlYjMudG9CaWdOdW1iZXIgPSB1dGlscy50b0JpZ051bWJlcjtcbndlYjMudG9XZWkgPSB1dGlscy50b1dlaTtcbndlYjMuZnJvbVdlaSA9IHV0aWxzLmZyb21XZWk7XG53ZWIzLmlzQWRkcmVzcyA9IHV0aWxzLmlzQWRkcmVzcztcbndlYjMuaXNJQkFOID0gdXRpbHMuaXNJQkFOO1xud2ViMy5zaGEzID0gc2hhMztcbndlYjMuY3JlYXRlQmF0Y2ggPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIG5ldyBCYXRjaCgpO1xufTtcblxuLy8gQUREIGRlZmF1bHRibG9ja1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KHdlYjMuZXRoLCAnZGVmYXVsdEJsb2NrJywge1xuICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gYy5kZWZhdWx0QmxvY2s7XG4gICAgfSxcbiAgICBzZXQ6IGZ1bmN0aW9uICh2YWwpIHtcbiAgICAgICAgYy5kZWZhdWx0QmxvY2sgPSB2YWw7XG4gICAgICAgIHJldHVybiB2YWw7XG4gICAgfVxufSk7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eSh3ZWIzLmV0aCwgJ2RlZmF1bHRBY2NvdW50Jywge1xuICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gYy5kZWZhdWx0QWNjb3VudDtcbiAgICB9LFxuICAgIHNldDogZnVuY3Rpb24gKHZhbCkge1xuICAgICAgICBjLmRlZmF1bHRBY2NvdW50ID0gdmFsO1xuICAgICAgICByZXR1cm4gdmFsO1xuICAgIH1cbn0pO1xuXG4vLy8gc2V0dXBzIGFsbCBhcGkgbWV0aG9kc1xuc2V0dXBQcm9wZXJ0aWVzKHdlYjMsIHdlYjNQcm9wZXJ0aWVzKTtcbnNldHVwTWV0aG9kcyh3ZWIzLm5ldCwgbmV0Lm1ldGhvZHMpO1xuc2V0dXBQcm9wZXJ0aWVzKHdlYjMubmV0LCBuZXQucHJvcGVydGllcyk7XG5zZXR1cE1ldGhvZHMod2ViMy5ldGgsIGV0aC5tZXRob2RzKTtcbnNldHVwUHJvcGVydGllcyh3ZWIzLmV0aCwgZXRoLnByb3BlcnRpZXMpO1xuc2V0dXBNZXRob2RzKHdlYjMuZGIsIGRiLm1ldGhvZHMpO1xuc2V0dXBNZXRob2RzKHdlYjMuc2hoLCBzaGgubWV0aG9kcyk7XG5cbndlYjMuYWRtaW4gPSB7fTtcbndlYjMuYWRtaW4uc2V0U2Vzc2lvbktleSA9IGZ1bmN0aW9uKHMpIHsgd2ViMy5hZG1pbi5zZXNzaW9uS2V5ID0gczsgfTtcblxudmFyIGJsb2NrUXVldWVTdGF0dXMgPSBuZXcgTWV0aG9kKHtcblx0bmFtZTogJ2Jsb2NrUXVldWVTdGF0dXMnLFxuXHRjYWxsOiAnYWRtaW5fZXRoX2Jsb2NrUXVldWVTdGF0dXMnLFxuXHRwYXJhbXM6IDEsXG5cdGlucHV0Rm9ybWF0dGVyOiBbZnVuY3Rpb24oKSB7IHJldHVybiB3ZWIzLmFkbWluLnNlc3Npb25LZXk7IH1dXG59KTtcblxuc2V0dXBNZXRob2RzKHdlYjMuYWRtaW4sIFtibG9ja1F1ZXVlU3RhdHVzXSk7XG5cbm1vZHVsZS5leHBvcnRzID0gd2ViMztcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogXG4gKiBAZmlsZSBiYXRjaC5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgUmVxdWVzdE1hbmFnZXIgPSByZXF1aXJlKCcuL3JlcXVlc3RtYW5hZ2VyJyk7XG5cbnZhciBCYXRjaCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnJlcXVlc3RzID0gW107XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gYWRkIGNyZWF0ZSBuZXcgcmVxdWVzdCB0byBiYXRjaCByZXF1ZXN0XG4gKlxuICogQG1ldGhvZCBhZGRcbiAqIEBwYXJhbSB7T2JqZWN0fSBqc29ucnBjIHJlcXVldCBvYmplY3RcbiAqL1xuQmF0Y2gucHJvdG90eXBlLmFkZCA9IGZ1bmN0aW9uIChyZXF1ZXN0KSB7XG4gICAgdGhpcy5yZXF1ZXN0cy5wdXNoKHJlcXVlc3QpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGV4ZWN1dGUgYmF0Y2ggcmVxdWVzdFxuICpcbiAqIEBtZXRob2QgZXhlY3V0ZVxuICovXG5CYXRjaC5wcm90b3R5cGUuZXhlY3V0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgcmVxdWVzdHMgPSB0aGlzLnJlcXVlc3RzO1xuICAgIFJlcXVlc3RNYW5hZ2VyLmdldEluc3RhbmNlKCkuc2VuZEJhdGNoKHJlcXVlc3RzLCBmdW5jdGlvbiAoZXJyLCByZXN1bHRzKSB7XG4gICAgICAgIHJlc3VsdHMgPSByZXN1bHRzIHx8IFtdO1xuICAgICAgICByZXF1ZXN0cy5tYXAoZnVuY3Rpb24gKHJlcXVlc3QsIGluZGV4KSB7XG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0c1tpbmRleF0gfHwge307XG4gICAgICAgIH0pLm1hcChmdW5jdGlvbiAocmVzdWx0LCBpbmRleCkge1xuICAgICAgICAgICAgcmV0dXJuIHJlcXVlc3RzW2luZGV4XS5mb3JtYXQgPyByZXF1ZXN0c1tpbmRleF0uZm9ybWF0KHJlc3VsdC5yZXN1bHQpIDogcmVzdWx0LnJlc3VsdDtcbiAgICAgICAgfSkuZm9yRWFjaChmdW5jdGlvbiAocmVzdWx0LCBpbmRleCkge1xuICAgICAgICAgICAgaWYgKHJlcXVlc3RzW2luZGV4XS5jYWxsYmFjaykge1xuICAgICAgICAgICAgICAgIHJlcXVlc3RzW2luZGV4XS5jYWxsYmFjayhlcnIsIHJlc3VsdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH0pOyBcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gQmF0Y2g7XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqIFxuICogQGZpbGUgY29udHJhY3QuanNcbiAqIEBhdXRob3IgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE0XG4gKi9cblxudmFyIHdlYjMgPSByZXF1aXJlKCcuLi93ZWIzJyk7IFxudmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMvdXRpbHMnKTtcbnZhciBjb2RlciA9IHJlcXVpcmUoJy4uL3NvbGlkaXR5L2NvZGVyJyk7XG52YXIgU29saWRpdHlFdmVudCA9IHJlcXVpcmUoJy4vZXZlbnQnKTtcbnZhciBTb2xpZGl0eUZ1bmN0aW9uID0gcmVxdWlyZSgnLi9mdW5jdGlvbicpO1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZW5jb2RlIGNvbnN0cnVjdG9yIHBhcmFtc1xuICpcbiAqIEBtZXRob2QgZW5jb2RlQ29uc3RydWN0b3JQYXJhbXNcbiAqIEBwYXJhbSB7QXJyYXl9IGFiaVxuICogQHBhcmFtIHtBcnJheX0gY29uc3RydWN0b3IgcGFyYW1zXG4gKi9cbnZhciBlbmNvZGVDb25zdHJ1Y3RvclBhcmFtcyA9IGZ1bmN0aW9uIChhYmksIHBhcmFtcykge1xuICAgIHJldHVybiBhYmkuZmlsdGVyKGZ1bmN0aW9uIChqc29uKSB7XG4gICAgICAgIHJldHVybiBqc29uLnR5cGUgPT09ICdjb25zdHJ1Y3RvcicgJiYganNvbi5pbnB1dHMubGVuZ3RoID09PSBwYXJhbXMubGVuZ3RoO1xuICAgIH0pLm1hcChmdW5jdGlvbiAoanNvbikge1xuICAgICAgICByZXR1cm4ganNvbi5pbnB1dHMubWFwKGZ1bmN0aW9uIChpbnB1dCkge1xuICAgICAgICAgICAgcmV0dXJuIGlucHV0LnR5cGU7XG4gICAgICAgIH0pO1xuICAgIH0pLm1hcChmdW5jdGlvbiAodHlwZXMpIHtcbiAgICAgICAgcmV0dXJuIGNvZGVyLmVuY29kZVBhcmFtcyh0eXBlcywgcGFyYW1zKTtcbiAgICB9KVswXSB8fCAnJztcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBhZGQgZnVuY3Rpb25zIHRvIGNvbnRyYWN0IG9iamVjdFxuICpcbiAqIEBtZXRob2QgYWRkRnVuY3Rpb25zVG9Db250cmFjdFxuICogQHBhcmFtIHtDb250cmFjdH0gY29udHJhY3RcbiAqIEBwYXJhbSB7QXJyYXl9IGFiaVxuICovXG52YXIgYWRkRnVuY3Rpb25zVG9Db250cmFjdCA9IGZ1bmN0aW9uIChjb250cmFjdCwgYWJpKSB7XG4gICAgYWJpLmZpbHRlcihmdW5jdGlvbiAoanNvbikge1xuICAgICAgICByZXR1cm4ganNvbi50eXBlID09PSAnZnVuY3Rpb24nO1xuICAgIH0pLm1hcChmdW5jdGlvbiAoanNvbikge1xuICAgICAgICByZXR1cm4gbmV3IFNvbGlkaXR5RnVuY3Rpb24oanNvbiwgY29udHJhY3QuYWRkcmVzcyk7XG4gICAgfSkuZm9yRWFjaChmdW5jdGlvbiAoZikge1xuICAgICAgICBmLmF0dGFjaFRvQ29udHJhY3QoY29udHJhY3QpO1xuICAgIH0pO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGFkZCBldmVudHMgdG8gY29udHJhY3Qgb2JqZWN0XG4gKlxuICogQG1ldGhvZCBhZGRFdmVudHNUb0NvbnRyYWN0XG4gKiBAcGFyYW0ge0NvbnRyYWN0fSBjb250cmFjdFxuICogQHBhcmFtIHtBcnJheX0gYWJpXG4gKi9cbnZhciBhZGRFdmVudHNUb0NvbnRyYWN0ID0gZnVuY3Rpb24gKGNvbnRyYWN0LCBhYmkpIHtcbiAgICBhYmkuZmlsdGVyKGZ1bmN0aW9uIChqc29uKSB7XG4gICAgICAgIHJldHVybiBqc29uLnR5cGUgPT09ICdldmVudCc7XG4gICAgfSkubWFwKGZ1bmN0aW9uIChqc29uKSB7XG4gICAgICAgIHJldHVybiBuZXcgU29saWRpdHlFdmVudChqc29uLCBjb250cmFjdC5hZGRyZXNzKTtcbiAgICB9KS5mb3JFYWNoKGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGUuYXR0YWNoVG9Db250cmFjdChjb250cmFjdCk7XG4gICAgfSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gY3JlYXRlIG5ldyBDb250cmFjdEZhY3RvcnlcbiAqXG4gKiBAbWV0aG9kIGNvbnRyYWN0XG4gKiBAcGFyYW0ge0FycmF5fSBhYmlcbiAqIEByZXR1cm5zIHtDb250cmFjdEZhY3Rvcnl9IG5ldyBjb250cmFjdCBmYWN0b3J5XG4gKi9cbnZhciBjb250cmFjdCA9IGZ1bmN0aW9uIChhYmkpIHtcbiAgICByZXR1cm4gbmV3IENvbnRyYWN0RmFjdG9yeShhYmkpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGNyZWF0ZSBuZXcgQ29udHJhY3RGYWN0b3J5IGluc3RhbmNlXG4gKlxuICogQG1ldGhvZCBDb250cmFjdEZhY3RvcnlcbiAqIEBwYXJhbSB7QXJyYXl9IGFiaVxuICovXG52YXIgQ29udHJhY3RGYWN0b3J5ID0gZnVuY3Rpb24gKGFiaSkge1xuICAgIHRoaXMuYWJpID0gYWJpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGNyZWF0ZSBuZXcgY29udHJhY3Qgb24gYSBibG9ja2NoYWluXG4gKiBcbiAqIEBtZXRob2QgbmV3XG4gKiBAcGFyYW0ge0FueX0gY29udHJhY3QgY29uc3RydWN0b3IgcGFyYW0xIChvcHRpb25hbClcbiAqIEBwYXJhbSB7QW55fSBjb250cmFjdCBjb25zdHJ1Y3RvciBwYXJhbTIgKG9wdGlvbmFsKVxuICogQHBhcmFtIHtPYmplY3R9IGNvbnRyYWN0IHRyYW5zYWN0aW9uIG9iamVjdCAocmVxdWlyZWQpXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFja1xuICogQHJldHVybnMge0NvbnRyYWN0fSByZXR1cm5zIGNvbnRyYWN0IGlmIG5vIGNhbGxiYWNrIHdhcyBwYXNzZWQsXG4gKiBvdGhlcndpc2UgY2FsbHMgY2FsbGJhY2sgZnVuY3Rpb24gKGVyciwgY29udHJhY3QpXG4gKi9cbkNvbnRyYWN0RmFjdG9yeS5wcm90b3R5cGUubmV3ID0gZnVuY3Rpb24gKCkge1xuICAgIC8vIHBhcnNlIGFyZ3VtZW50c1xuICAgIHZhciBvcHRpb25zID0ge307IC8vIHJlcXVpcmVkIVxuICAgIHZhciBjYWxsYmFjaztcblxuICAgIHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKTtcbiAgICBpZiAodXRpbHMuaXNGdW5jdGlvbihhcmdzW2FyZ3MubGVuZ3RoIC0gMV0pKSB7XG4gICAgICAgIGNhbGxiYWNrID0gYXJncy5wb3AoKTtcbiAgICB9XG5cbiAgICB2YXIgbGFzdCA9IGFyZ3NbYXJncy5sZW5ndGggLSAxXTtcbiAgICBpZiAodXRpbHMuaXNPYmplY3QobGFzdCkgJiYgIXV0aWxzLmlzQXJyYXkobGFzdCkpIHtcbiAgICAgICAgb3B0aW9ucyA9IGFyZ3MucG9wKCk7XG4gICAgfVxuXG4gICAgLy8gdGhyb3cgYW4gZXJyb3IgaWYgdGhlcmUgYXJlIG5vIG9wdGlvbnNcblxuICAgIHZhciBieXRlcyA9IGVuY29kZUNvbnN0cnVjdG9yUGFyYW1zKHRoaXMuYWJpLCBhcmdzKTtcbiAgICBvcHRpb25zLmRhdGEgKz0gYnl0ZXM7XG5cbiAgICBpZiAoIWNhbGxiYWNrKSB7XG4gICAgICAgIHZhciBhZGRyZXNzID0gd2ViMy5ldGguc2VuZFRyYW5zYWN0aW9uKG9wdGlvbnMpO1xuICAgICAgICByZXR1cm4gdGhpcy5hdChhZGRyZXNzKTtcbiAgICB9XG4gIFxuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB3ZWIzLmV0aC5zZW5kVHJhbnNhY3Rpb24ob3B0aW9ucywgZnVuY3Rpb24gKGVyciwgYWRkcmVzcykge1xuICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICBjYWxsYmFjayhlcnIpO1xuICAgICAgICB9XG4gICAgICAgIHNlbGYuYXQoYWRkcmVzcywgY2FsbGJhY2spOyBcbiAgICB9KTsgXG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZ2V0IGFjY2VzcyB0byBleGlzdGluZyBjb250cmFjdCBvbiBhIGJsb2NrY2hhaW5cbiAqXG4gKiBAbWV0aG9kIGF0XG4gKiBAcGFyYW0ge0FkZHJlc3N9IGNvbnRyYWN0IGFkZHJlc3MgKHJlcXVpcmVkKVxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sge29wdGlvbmFsKVxuICogQHJldHVybnMge0NvbnRyYWN0fSByZXR1cm5zIGNvbnRyYWN0IGlmIG5vIGNhbGxiYWNrIHdhcyBwYXNzZWQsXG4gKiBvdGhlcndpc2UgY2FsbHMgY2FsbGJhY2sgZnVuY3Rpb24gKGVyciwgY29udHJhY3QpXG4gKi9cbkNvbnRyYWN0RmFjdG9yeS5wcm90b3R5cGUuYXQgPSBmdW5jdGlvbiAoYWRkcmVzcywgY2FsbGJhY2spIHtcbiAgICAvLyBUT0RPOiBhZGRyZXNzIGlzIHJlcXVpcmVkXG4gICAgXG4gICAgaWYgKGNhbGxiYWNrKSB7XG4gICAgICAgIGNhbGxiYWNrKG51bGwsIG5ldyBDb250cmFjdCh0aGlzLmFiaSwgYWRkcmVzcykpO1xuICAgIH0gXG4gICAgcmV0dXJuIG5ldyBDb250cmFjdCh0aGlzLmFiaSwgYWRkcmVzcyk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gY3JlYXRlIG5ldyBjb250cmFjdCBpbnN0YW5jZVxuICpcbiAqIEBtZXRob2QgQ29udHJhY3RcbiAqIEBwYXJhbSB7QXJyYXl9IGFiaVxuICogQHBhcmFtIHtBZGRyZXNzfSBjb250cmFjdCBhZGRyZXNzXG4gKi9cbnZhciBDb250cmFjdCA9IGZ1bmN0aW9uIChhYmksIGFkZHJlc3MpIHtcbiAgICB0aGlzLmFkZHJlc3MgPSBhZGRyZXNzO1xuICAgIGFkZEZ1bmN0aW9uc1RvQ29udHJhY3QodGhpcywgYWJpKTtcbiAgICBhZGRFdmVudHNUb0NvbnRyYWN0KHRoaXMsIGFiaSk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNvbnRyYWN0O1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBAZmlsZSBkYi5qc1xuICogQGF1dGhvcnM6XG4gKiAgIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbnZhciBNZXRob2QgPSByZXF1aXJlKCcuL21ldGhvZCcpO1xuXG52YXIgcHV0U3RyaW5nID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ3B1dFN0cmluZycsXG4gICAgY2FsbDogJ2RiX3B1dFN0cmluZycsXG4gICAgcGFyYW1zOiAzXG59KTtcblxuXG52YXIgZ2V0U3RyaW5nID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2dldFN0cmluZycsXG4gICAgY2FsbDogJ2RiX2dldFN0cmluZycsXG4gICAgcGFyYW1zOiAyXG59KTtcblxudmFyIHB1dEhleCA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdwdXRIZXgnLFxuICAgIGNhbGw6ICdkYl9wdXRIZXgnLFxuICAgIHBhcmFtczogM1xufSk7XG5cbnZhciBnZXRIZXggPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnZ2V0SGV4JyxcbiAgICBjYWxsOiAnZGJfZ2V0SGV4JyxcbiAgICBwYXJhbXM6IDJcbn0pO1xuXG52YXIgbWV0aG9kcyA9IFtcbiAgICBwdXRTdHJpbmcsIGdldFN0cmluZywgcHV0SGV4LCBnZXRIZXhcbl07XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIG1ldGhvZHM6IG1ldGhvZHNcbn07XG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBcbiAqIEBmaWxlIGVycm9ycy5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBJbnZhbGlkTnVtYmVyT2ZQYXJhbXM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBFcnJvcignSW52YWxpZCBudW1iZXIgb2YgaW5wdXQgcGFyYW1ldGVycycpO1xuICAgIH0sXG4gICAgSW52YWxpZENvbm5lY3Rpb246IGZ1bmN0aW9uIChob3N0KXtcbiAgICAgICAgcmV0dXJuIG5ldyBFcnJvcignQ09OTkVDVElPTiBFUlJPUjogQ291bGRuXFwndCBjb25uZWN0IHRvIG5vZGUgJysgaG9zdCArJywgaXMgaXQgcnVubmluZz8nKTtcbiAgICB9LFxuICAgIEludmFsaWRQcm92aWRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gbmV3IEVycm9yKCdQcm92aWRvciBub3Qgc2V0IG9yIGludmFsaWQnKTtcbiAgICB9LFxuICAgIEludmFsaWRSZXNwb25zZTogZnVuY3Rpb24gKHJlc3VsdCl7XG4gICAgICAgIHZhciBtZXNzYWdlID0gISFyZXN1bHQgJiYgISFyZXN1bHQuZXJyb3IgJiYgISFyZXN1bHQuZXJyb3IubWVzc2FnZSA/IHJlc3VsdC5lcnJvci5tZXNzYWdlIDogJ0ludmFsaWQgSlNPTiBSUEMgcmVzcG9uc2UnO1xuICAgICAgICByZXR1cm4gbmV3IEVycm9yKG1lc3NhZ2UpO1xuICAgIH1cbn07XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqXG4gKiBAZmlsZSBldGguanNcbiAqIEBhdXRob3IgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiBAYXV0aG9yIEZhYmlhbiBWb2dlbHN0ZWxsZXIgPGZhYmlhbkBldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbi8qKlxuICogV2ViM1xuICpcbiAqIEBtb2R1bGUgd2ViM1xuICovXG5cbi8qKlxuICogRXRoIG1ldGhvZHMgYW5kIHByb3BlcnRpZXNcbiAqXG4gKiBBbiBleGFtcGxlIG1ldGhvZCBvYmplY3QgY2FuIGxvb2sgYXMgZm9sbG93czpcbiAqXG4gKiAgICAgIHtcbiAqICAgICAgbmFtZTogJ2dldEJsb2NrJyxcbiAqICAgICAgY2FsbDogYmxvY2tDYWxsLFxuICogICAgICBwYXJhbXM6IDIsXG4gKiAgICAgIG91dHB1dEZvcm1hdHRlcjogZm9ybWF0dGVycy5vdXRwdXRCbG9ja0Zvcm1hdHRlcixcbiAqICAgICAgaW5wdXRGb3JtYXR0ZXI6IFsgLy8gY2FuIGJlIGEgZm9ybWF0dGVyIGZ1bmNpdG9uIG9yIGFuIGFycmF5IG9mIGZ1bmN0aW9ucy4gV2hlcmUgZWFjaCBpdGVtIGluIHRoZSBhcnJheSB3aWxsIGJlIHVzZWQgZm9yIG9uZSBwYXJhbWV0ZXJcbiAqICAgICAgICAgICB1dGlscy50b0hleCwgLy8gZm9ybWF0cyBwYXJhbXRlciAxXG4gKiAgICAgICAgICAgZnVuY3Rpb24ocGFyYW0peyByZXR1cm4gISFwYXJhbTsgfSAvLyBmb3JtYXRzIHBhcmFtdGVyIDJcbiAqICAgICAgICAgXVxuICogICAgICAgfSxcbiAqXG4gKiBAY2xhc3MgW3dlYjNdIGV0aFxuICogQGNvbnN0cnVjdG9yXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBmb3JtYXR0ZXJzID0gcmVxdWlyZSgnLi9mb3JtYXR0ZXJzJyk7XG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy91dGlscycpO1xudmFyIE1ldGhvZCA9IHJlcXVpcmUoJy4vbWV0aG9kJyk7XG52YXIgUHJvcGVydHkgPSByZXF1aXJlKCcuL3Byb3BlcnR5Jyk7XG5cbnZhciBibG9ja0NhbGwgPSBmdW5jdGlvbiAoYXJncykge1xuICAgIHJldHVybiAodXRpbHMuaXNTdHJpbmcoYXJnc1swXSkgJiYgYXJnc1swXS5pbmRleE9mKCcweCcpID09PSAwKSA/IFwiZXRoX2dldEJsb2NrQnlIYXNoXCIgOiBcImV0aF9nZXRCbG9ja0J5TnVtYmVyXCI7XG59O1xuXG52YXIgdHJhbnNhY3Rpb25Gcm9tQmxvY2tDYWxsID0gZnVuY3Rpb24gKGFyZ3MpIHtcbiAgICByZXR1cm4gKHV0aWxzLmlzU3RyaW5nKGFyZ3NbMF0pICYmIGFyZ3NbMF0uaW5kZXhPZignMHgnKSA9PT0gMCkgPyAnZXRoX2dldFRyYW5zYWN0aW9uQnlCbG9ja0hhc2hBbmRJbmRleCcgOiAnZXRoX2dldFRyYW5zYWN0aW9uQnlCbG9ja051bWJlckFuZEluZGV4Jztcbn07XG5cbnZhciB1bmNsZUNhbGwgPSBmdW5jdGlvbiAoYXJncykge1xuICAgIHJldHVybiAodXRpbHMuaXNTdHJpbmcoYXJnc1swXSkgJiYgYXJnc1swXS5pbmRleE9mKCcweCcpID09PSAwKSA/ICdldGhfZ2V0VW5jbGVCeUJsb2NrSGFzaEFuZEluZGV4JyA6ICdldGhfZ2V0VW5jbGVCeUJsb2NrTnVtYmVyQW5kSW5kZXgnO1xufTtcblxudmFyIGdldEJsb2NrVHJhbnNhY3Rpb25Db3VudENhbGwgPSBmdW5jdGlvbiAoYXJncykge1xuICAgIHJldHVybiAodXRpbHMuaXNTdHJpbmcoYXJnc1swXSkgJiYgYXJnc1swXS5pbmRleE9mKCcweCcpID09PSAwKSA/ICdldGhfZ2V0QmxvY2tUcmFuc2FjdGlvbkNvdW50QnlIYXNoJyA6ICdldGhfZ2V0QmxvY2tUcmFuc2FjdGlvbkNvdW50QnlOdW1iZXInO1xufTtcblxudmFyIHVuY2xlQ291bnRDYWxsID0gZnVuY3Rpb24gKGFyZ3MpIHtcbiAgICByZXR1cm4gKHV0aWxzLmlzU3RyaW5nKGFyZ3NbMF0pICYmIGFyZ3NbMF0uaW5kZXhPZignMHgnKSA9PT0gMCkgPyAnZXRoX2dldFVuY2xlQ291bnRCeUJsb2NrSGFzaCcgOiAnZXRoX2dldFVuY2xlQ291bnRCeUJsb2NrTnVtYmVyJztcbn07XG5cbi8vLyBAcmV0dXJucyBhbiBhcnJheSBvZiBvYmplY3RzIGRlc2NyaWJpbmcgd2ViMy5ldGggYXBpIG1ldGhvZHNcblxudmFyIGdldEJhbGFuY2UgPSBuZXcgTWV0aG9kKHtcblx0bmFtZTogJ2dldEJhbGFuY2UnLFxuXHRjYWxsOiAnZXRoX2dldEJhbGFuY2UnLFxuXHRwYXJhbXM6IDIsXG5cdGlucHV0Rm9ybWF0dGVyOiBbdXRpbHMudG9BZGRyZXNzLCBmb3JtYXR0ZXJzLmlucHV0RGVmYXVsdEJsb2NrTnVtYmVyRm9ybWF0dGVyXSxcblx0b3V0cHV0Rm9ybWF0dGVyOiBmb3JtYXR0ZXJzLm91dHB1dEJpZ051bWJlckZvcm1hdHRlclxufSk7XG5cbnZhciBnZXRTdG9yYWdlQXQgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnZ2V0U3RvcmFnZUF0JyxcbiAgICBjYWxsOiAnZXRoX2dldFN0b3JhZ2VBdCcsXG4gICAgcGFyYW1zOiAzLFxuICAgIGlucHV0Rm9ybWF0dGVyOiBbbnVsbCwgdXRpbHMudG9IZXgsIGZvcm1hdHRlcnMuaW5wdXREZWZhdWx0QmxvY2tOdW1iZXJGb3JtYXR0ZXJdXG59KTtcblxudmFyIGdldENvZGUgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnZ2V0Q29kZScsXG4gICAgY2FsbDogJ2V0aF9nZXRDb2RlJyxcbiAgICBwYXJhbXM6IDIsXG4gICAgaW5wdXRGb3JtYXR0ZXI6IFt1dGlscy50b0FkZHJlc3MsIGZvcm1hdHRlcnMuaW5wdXREZWZhdWx0QmxvY2tOdW1iZXJGb3JtYXR0ZXJdXG59KTtcblxudmFyIGdldEJsb2NrID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2dldEJsb2NrJyxcbiAgICBjYWxsOiBibG9ja0NhbGwsXG4gICAgcGFyYW1zOiAyLFxuICAgIGlucHV0Rm9ybWF0dGVyOiBbZm9ybWF0dGVycy5pbnB1dEJsb2NrTnVtYmVyRm9ybWF0dGVyLCBmdW5jdGlvbiAodmFsKSB7IHJldHVybiAhIXZhbDsgfV0sXG4gICAgb3V0cHV0Rm9ybWF0dGVyOiBmb3JtYXR0ZXJzLm91dHB1dEJsb2NrRm9ybWF0dGVyXG59KTtcblxudmFyIGdldFVuY2xlID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2dldFVuY2xlJyxcbiAgICBjYWxsOiB1bmNsZUNhbGwsXG4gICAgcGFyYW1zOiAyLFxuICAgIGlucHV0Rm9ybWF0dGVyOiBbZm9ybWF0dGVycy5pbnB1dEJsb2NrTnVtYmVyRm9ybWF0dGVyLCB1dGlscy50b0hleF0sXG4gICAgb3V0cHV0Rm9ybWF0dGVyOiBmb3JtYXR0ZXJzLm91dHB1dEJsb2NrRm9ybWF0dGVyLFxuXG59KTtcblxudmFyIGdldENvbXBpbGVycyA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdnZXRDb21waWxlcnMnLFxuICAgIGNhbGw6ICdldGhfZ2V0Q29tcGlsZXJzJyxcbiAgICBwYXJhbXM6IDBcbn0pO1xuXG52YXIgZ2V0QmxvY2tUcmFuc2FjdGlvbkNvdW50ID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2dldEJsb2NrVHJhbnNhY3Rpb25Db3VudCcsXG4gICAgY2FsbDogZ2V0QmxvY2tUcmFuc2FjdGlvbkNvdW50Q2FsbCxcbiAgICBwYXJhbXM6IDEsXG4gICAgaW5wdXRGb3JtYXR0ZXI6IFtmb3JtYXR0ZXJzLmlucHV0QmxvY2tOdW1iZXJGb3JtYXR0ZXJdLFxuICAgIG91dHB1dEZvcm1hdHRlcjogdXRpbHMudG9EZWNpbWFsXG59KTtcblxudmFyIGdldEJsb2NrVW5jbGVDb3VudCA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdnZXRCbG9ja1VuY2xlQ291bnQnLFxuICAgIGNhbGw6IHVuY2xlQ291bnRDYWxsLFxuICAgIHBhcmFtczogMSxcbiAgICBpbnB1dEZvcm1hdHRlcjogW2Zvcm1hdHRlcnMuaW5wdXRCbG9ja051bWJlckZvcm1hdHRlcl0sXG4gICAgb3V0cHV0Rm9ybWF0dGVyOiB1dGlscy50b0RlY2ltYWxcbn0pO1xuXG52YXIgZ2V0VHJhbnNhY3Rpb24gPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnZ2V0VHJhbnNhY3Rpb24nLFxuICAgIGNhbGw6ICdldGhfZ2V0VHJhbnNhY3Rpb25CeUhhc2gnLFxuICAgIHBhcmFtczogMSxcbiAgICBvdXRwdXRGb3JtYXR0ZXI6IGZvcm1hdHRlcnMub3V0cHV0VHJhbnNhY3Rpb25Gb3JtYXR0ZXJcbn0pO1xuXG52YXIgZ2V0VHJhbnNhY3Rpb25Gcm9tQmxvY2sgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnZ2V0VHJhbnNhY3Rpb25Gcm9tQmxvY2snLFxuICAgIGNhbGw6IHRyYW5zYWN0aW9uRnJvbUJsb2NrQ2FsbCxcbiAgICBwYXJhbXM6IDIsXG4gICAgaW5wdXRGb3JtYXR0ZXI6IFtmb3JtYXR0ZXJzLmlucHV0QmxvY2tOdW1iZXJGb3JtYXR0ZXIsIHV0aWxzLnRvSGV4XSxcbiAgICBvdXRwdXRGb3JtYXR0ZXI6IGZvcm1hdHRlcnMub3V0cHV0VHJhbnNhY3Rpb25Gb3JtYXR0ZXJcbn0pO1xuXG52YXIgZ2V0VHJhbnNhY3Rpb25Db3VudCA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdnZXRUcmFuc2FjdGlvbkNvdW50JyxcbiAgICBjYWxsOiAnZXRoX2dldFRyYW5zYWN0aW9uQ291bnQnLFxuICAgIHBhcmFtczogMixcbiAgICBpbnB1dEZvcm1hdHRlcjogW251bGwsIGZvcm1hdHRlcnMuaW5wdXREZWZhdWx0QmxvY2tOdW1iZXJGb3JtYXR0ZXJdLFxuICAgIG91dHB1dEZvcm1hdHRlcjogdXRpbHMudG9EZWNpbWFsXG59KTtcblxudmFyIHNlbmRUcmFuc2FjdGlvbiA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdzZW5kVHJhbnNhY3Rpb24nLFxuICAgIGNhbGw6ICdldGhfc2VuZFRyYW5zYWN0aW9uJyxcbiAgICBwYXJhbXM6IDEsXG4gICAgaW5wdXRGb3JtYXR0ZXI6IFtmb3JtYXR0ZXJzLmlucHV0VHJhbnNhY3Rpb25Gb3JtYXR0ZXJdXG59KTtcblxudmFyIGNhbGwgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnY2FsbCcsXG4gICAgY2FsbDogJ2V0aF9jYWxsJyxcbiAgICBwYXJhbXM6IDIsXG4gICAgaW5wdXRGb3JtYXR0ZXI6IFtmb3JtYXR0ZXJzLmlucHV0VHJhbnNhY3Rpb25Gb3JtYXR0ZXIsIGZvcm1hdHRlcnMuaW5wdXREZWZhdWx0QmxvY2tOdW1iZXJGb3JtYXR0ZXJdXG59KTtcblxudmFyIGVzdGltYXRlR2FzID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2VzdGltYXRlR2FzJyxcbiAgICBjYWxsOiAnZXRoX2VzdGltYXRlR2FzJyxcbiAgICBwYXJhbXM6IDEsXG4gICAgaW5wdXRGb3JtYXR0ZXI6IFtmb3JtYXR0ZXJzLmlucHV0VHJhbnNhY3Rpb25Gb3JtYXR0ZXJdLFxuICAgIG91dHB1dEZvcm1hdHRlcjogdXRpbHMudG9EZWNpbWFsXG59KTtcblxudmFyIGNvbXBpbGVTb2xpZGl0eSA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdjb21waWxlLnNvbGlkaXR5JyxcbiAgICBjYWxsOiAnZXRoX2NvbXBpbGVTb2xpZGl0eScsXG4gICAgcGFyYW1zOiAxXG59KTtcblxudmFyIGNvbXBpbGVMTEwgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnY29tcGlsZS5sbGwnLFxuICAgIGNhbGw6ICdldGhfY29tcGlsZUxMTCcsXG4gICAgcGFyYW1zOiAxXG59KTtcblxudmFyIGNvbXBpbGVTZXJwZW50ID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2NvbXBpbGUuc2VycGVudCcsXG4gICAgY2FsbDogJ2V0aF9jb21waWxlU2VycGVudCcsXG4gICAgcGFyYW1zOiAxXG59KTtcblxudmFyIHN1Ym1pdFdvcmsgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnc3VibWl0V29yaycsXG4gICAgY2FsbDogJ2V0aF9zdWJtaXRXb3JrJyxcbiAgICBwYXJhbXM6IDNcbn0pO1xuXG52YXIgZ2V0V29yayA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICdnZXRXb3JrJyxcbiAgICBjYWxsOiAnZXRoX2dldFdvcmsnLFxuICAgIHBhcmFtczogMFxufSk7XG5cbnZhciBtZXRob2RzID0gW1xuICAgIGdldEJhbGFuY2UsXG4gICAgZ2V0U3RvcmFnZUF0LFxuICAgIGdldENvZGUsXG4gICAgZ2V0QmxvY2ssXG4gICAgZ2V0VW5jbGUsXG4gICAgZ2V0Q29tcGlsZXJzLFxuICAgIGdldEJsb2NrVHJhbnNhY3Rpb25Db3VudCxcbiAgICBnZXRCbG9ja1VuY2xlQ291bnQsXG4gICAgZ2V0VHJhbnNhY3Rpb24sXG4gICAgZ2V0VHJhbnNhY3Rpb25Gcm9tQmxvY2ssXG4gICAgZ2V0VHJhbnNhY3Rpb25Db3VudCxcbiAgICBjYWxsLFxuICAgIGVzdGltYXRlR2FzLFxuICAgIHNlbmRUcmFuc2FjdGlvbixcbiAgICBjb21waWxlU29saWRpdHksXG4gICAgY29tcGlsZUxMTCxcbiAgICBjb21waWxlU2VycGVudCxcbiAgICBzdWJtaXRXb3JrLFxuICAgIGdldFdvcmtcbl07XG5cbi8vLyBAcmV0dXJucyBhbiBhcnJheSBvZiBvYmplY3RzIGRlc2NyaWJpbmcgd2ViMy5ldGggYXBpIHByb3BlcnRpZXNcblxuXG5cbnZhciBwcm9wZXJ0aWVzID0gW1xuICAgIG5ldyBQcm9wZXJ0eSh7XG4gICAgICAgIG5hbWU6ICdjb2luYmFzZScsXG4gICAgICAgIGdldHRlcjogJ2V0aF9jb2luYmFzZSdcbiAgICB9KSxcbiAgICBuZXcgUHJvcGVydHkoe1xuICAgICAgICBuYW1lOiAnbWluaW5nJyxcbiAgICAgICAgZ2V0dGVyOiAnZXRoX21pbmluZydcbiAgICB9KSxcbiAgICBuZXcgUHJvcGVydHkoe1xuICAgICAgICBuYW1lOiAnaGFzaHJhdGUnLFxuICAgICAgICBnZXR0ZXI6ICdldGhfaGFzaHJhdGUnLFxuICAgICAgICBvdXRwdXRGb3JtYXR0ZXI6IHV0aWxzLnRvRGVjaW1hbFxuICAgIH0pLFxuICAgIG5ldyBQcm9wZXJ0eSh7XG4gICAgICAgIG5hbWU6ICdnYXNQcmljZScsXG4gICAgICAgIGdldHRlcjogJ2V0aF9nYXNQcmljZScsXG4gICAgICAgIG91dHB1dEZvcm1hdHRlcjogZm9ybWF0dGVycy5vdXRwdXRCaWdOdW1iZXJGb3JtYXR0ZXJcbiAgICB9KSxcbiAgICBuZXcgUHJvcGVydHkoe1xuICAgICAgICBuYW1lOiAnYWNjb3VudHMnLFxuICAgICAgICBnZXR0ZXI6ICdldGhfYWNjb3VudHMnXG4gICAgfSksXG4gICAgbmV3IFByb3BlcnR5KHtcbiAgICAgICAgbmFtZTogJ2Jsb2NrTnVtYmVyJyxcbiAgICAgICAgZ2V0dGVyOiAnZXRoX2Jsb2NrTnVtYmVyJyxcbiAgICAgICAgb3V0cHV0Rm9ybWF0dGVyOiB1dGlscy50b0RlY2ltYWxcbiAgICB9KVxuXTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgbWV0aG9kczogbWV0aG9kcyxcbiAgICBwcm9wZXJ0aWVzOiBwcm9wZXJ0aWVzXG59O1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBcbiAqIEBmaWxlIGV2ZW50LmpzXG4gKiBAYXV0aG9yIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNFxuICovXG5cbnZhciB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzL3V0aWxzJyk7XG52YXIgY29kZXIgPSByZXF1aXJlKCcuLi9zb2xpZGl0eS9jb2RlcicpO1xudmFyIHdlYjMgPSByZXF1aXJlKCcuLi93ZWIzJyk7XG52YXIgZm9ybWF0dGVycyA9IHJlcXVpcmUoJy4vZm9ybWF0dGVycycpO1xudmFyIHNoYTMgPSByZXF1aXJlKCcuLi91dGlscy9zaGEzJyk7XG5cbi8qKlxuICogVGhpcyBwcm90b3R5cGUgc2hvdWxkIGJlIHVzZWQgdG8gY3JlYXRlIGV2ZW50IGZpbHRlcnNcbiAqL1xudmFyIFNvbGlkaXR5RXZlbnQgPSBmdW5jdGlvbiAoanNvbiwgYWRkcmVzcykge1xuICAgIHRoaXMuX3BhcmFtcyA9IGpzb24uaW5wdXRzO1xuICAgIHRoaXMuX25hbWUgPSB1dGlscy50cmFuc2Zvcm1Ub0Z1bGxOYW1lKGpzb24pO1xuICAgIHRoaXMuX2FkZHJlc3MgPSBhZGRyZXNzO1xuICAgIHRoaXMuX2Fub255bW91cyA9IGpzb24uYW5vbnltb3VzO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBnZXQgZmlsdGVyZWQgcGFyYW0gdHlwZXNcbiAqXG4gKiBAbWV0aG9kIHR5cGVzXG4gKiBAcGFyYW0ge0Jvb2x9IGRlY2lkZSBpZiByZXR1cm5lZCB0eXBlZCBzaG91bGQgYmUgaW5kZXhlZFxuICogQHJldHVybiB7QXJyYXl9IGFycmF5IG9mIHR5cGVzXG4gKi9cblNvbGlkaXR5RXZlbnQucHJvdG90eXBlLnR5cGVzID0gZnVuY3Rpb24gKGluZGV4ZWQpIHtcbiAgICByZXR1cm4gdGhpcy5fcGFyYW1zLmZpbHRlcihmdW5jdGlvbiAoaSkge1xuICAgICAgICByZXR1cm4gaS5pbmRleGVkID09PSBpbmRleGVkO1xuICAgIH0pLm1hcChmdW5jdGlvbiAoaSkge1xuICAgICAgICByZXR1cm4gaS50eXBlO1xuICAgIH0pO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBnZXQgZXZlbnQgZGlzcGxheSBuYW1lXG4gKlxuICogQG1ldGhvZCBkaXNwbGF5TmFtZVxuICogQHJldHVybiB7U3RyaW5nfSBldmVudCBkaXNwbGF5IG5hbWVcbiAqL1xuU29saWRpdHlFdmVudC5wcm90b3R5cGUuZGlzcGxheU5hbWUgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHV0aWxzLmV4dHJhY3REaXNwbGF5TmFtZSh0aGlzLl9uYW1lKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZ2V0IGV2ZW50IHR5cGUgbmFtZVxuICpcbiAqIEBtZXRob2QgdHlwZU5hbWVcbiAqIEByZXR1cm4ge1N0cmluZ30gZXZlbnQgdHlwZSBuYW1lXG4gKi9cblNvbGlkaXR5RXZlbnQucHJvdG90eXBlLnR5cGVOYW1lID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB1dGlscy5leHRyYWN0VHlwZU5hbWUodGhpcy5fbmFtZSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGdldCBldmVudCBzaWduYXR1cmVcbiAqXG4gKiBAbWV0aG9kIHNpZ25hdHVyZVxuICogQHJldHVybiB7U3RyaW5nfSBldmVudCBzaWduYXR1cmVcbiAqL1xuU29saWRpdHlFdmVudC5wcm90b3R5cGUuc2lnbmF0dXJlID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBzaGEzKHRoaXMuX25hbWUpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBlbmNvZGUgaW5kZXhlZCBwYXJhbXMgYW5kIG9wdGlvbnMgdG8gb25lIGZpbmFsIG9iamVjdFxuICogXG4gKiBAbWV0aG9kIGVuY29kZVxuICogQHBhcmFtIHtPYmplY3R9IGluZGV4ZWRcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zXG4gKiBAcmV0dXJuIHtPYmplY3R9IGV2ZXJ5dGhpbmcgY29tYmluZWQgdG9nZXRoZXIgYW5kIGVuY29kZWRcbiAqL1xuU29saWRpdHlFdmVudC5wcm90b3R5cGUuZW5jb2RlID0gZnVuY3Rpb24gKGluZGV4ZWQsIG9wdGlvbnMpIHtcbiAgICBpbmRleGVkID0gaW5kZXhlZCB8fCB7fTtcbiAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICB2YXIgcmVzdWx0ID0ge307XG5cbiAgICBbJ2Zyb21CbG9jaycsICd0b0Jsb2NrJ10uZmlsdGVyKGZ1bmN0aW9uIChmKSB7XG4gICAgICAgIHJldHVybiBvcHRpb25zW2ZdICE9PSB1bmRlZmluZWQ7XG4gICAgfSkuZm9yRWFjaChmdW5jdGlvbiAoZikge1xuICAgICAgICByZXN1bHRbZl0gPSBmb3JtYXR0ZXJzLmlucHV0QmxvY2tOdW1iZXJGb3JtYXR0ZXIob3B0aW9uc1tmXSk7XG4gICAgfSk7XG5cbiAgICByZXN1bHQudG9waWNzID0gW107XG5cbiAgICBpZiAoIXRoaXMuX2Fub255bW91cykge1xuICAgICAgICByZXN1bHQuYWRkcmVzcyA9IHRoaXMuX2FkZHJlc3M7XG4gICAgICAgIHJlc3VsdC50b3BpY3MucHVzaCgnMHgnICsgdGhpcy5zaWduYXR1cmUoKSk7XG4gICAgfVxuXG4gICAgdmFyIGluZGV4ZWRUb3BpY3MgPSB0aGlzLl9wYXJhbXMuZmlsdGVyKGZ1bmN0aW9uIChpKSB7XG4gICAgICAgIHJldHVybiBpLmluZGV4ZWQgPT09IHRydWU7XG4gICAgfSkubWFwKGZ1bmN0aW9uIChpKSB7XG4gICAgICAgIHZhciB2YWx1ZSA9IGluZGV4ZWRbaS5uYW1lXTtcbiAgICAgICAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQgfHwgdmFsdWUgPT09IG51bGwpIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICBpZiAodXRpbHMuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgICAgICAgIHJldHVybiB2YWx1ZS5tYXAoZnVuY3Rpb24gKHYpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gJzB4JyArIGNvZGVyLmVuY29kZVBhcmFtKGkudHlwZSwgdik7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gJzB4JyArIGNvZGVyLmVuY29kZVBhcmFtKGkudHlwZSwgdmFsdWUpO1xuICAgIH0pO1xuXG4gICAgcmVzdWx0LnRvcGljcyA9IHJlc3VsdC50b3BpY3MuY29uY2F0KGluZGV4ZWRUb3BpY3MpO1xuXG4gICAgcmV0dXJuIHJlc3VsdDtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZGVjb2RlIGluZGV4ZWQgcGFyYW1zIGFuZCBvcHRpb25zXG4gKlxuICogQG1ldGhvZCBkZWNvZGVcbiAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhXG4gKiBAcmV0dXJuIHtPYmplY3R9IHJlc3VsdCBvYmplY3Qgd2l0aCBkZWNvZGVkIGluZGV4ZWQgJiYgbm90IGluZGV4ZWQgcGFyYW1zXG4gKi9cblNvbGlkaXR5RXZlbnQucHJvdG90eXBlLmRlY29kZSA9IGZ1bmN0aW9uIChkYXRhKSB7XG4gXG4gICAgZGF0YS5kYXRhID0gZGF0YS5kYXRhIHx8ICcnO1xuICAgIGRhdGEudG9waWNzID0gZGF0YS50b3BpY3MgfHwgW107XG5cbiAgICB2YXIgYXJnVG9waWNzID0gdGhpcy5fYW5vbnltb3VzID8gZGF0YS50b3BpY3MgOiBkYXRhLnRvcGljcy5zbGljZSgxKTtcbiAgICB2YXIgaW5kZXhlZERhdGEgPSBhcmdUb3BpY3MubWFwKGZ1bmN0aW9uICh0b3BpY3MpIHsgcmV0dXJuIHRvcGljcy5zbGljZSgyKTsgfSkuam9pbihcIlwiKTtcbiAgICB2YXIgaW5kZXhlZFBhcmFtcyA9IGNvZGVyLmRlY29kZVBhcmFtcyh0aGlzLnR5cGVzKHRydWUpLCBpbmRleGVkRGF0YSk7IFxuXG4gICAgdmFyIG5vdEluZGV4ZWREYXRhID0gZGF0YS5kYXRhLnNsaWNlKDIpO1xuICAgIHZhciBub3RJbmRleGVkUGFyYW1zID0gY29kZXIuZGVjb2RlUGFyYW1zKHRoaXMudHlwZXMoZmFsc2UpLCBub3RJbmRleGVkRGF0YSk7XG4gICAgXG4gICAgdmFyIHJlc3VsdCA9IGZvcm1hdHRlcnMub3V0cHV0TG9nRm9ybWF0dGVyKGRhdGEpO1xuICAgIHJlc3VsdC5ldmVudCA9IHRoaXMuZGlzcGxheU5hbWUoKTtcbiAgICByZXN1bHQuYWRkcmVzcyA9IGRhdGEuYWRkcmVzcztcblxuICAgIHJlc3VsdC5hcmdzID0gdGhpcy5fcGFyYW1zLnJlZHVjZShmdW5jdGlvbiAoYWNjLCBjdXJyZW50KSB7XG4gICAgICAgIGFjY1tjdXJyZW50Lm5hbWVdID0gY3VycmVudC5pbmRleGVkID8gaW5kZXhlZFBhcmFtcy5zaGlmdCgpIDogbm90SW5kZXhlZFBhcmFtcy5zaGlmdCgpO1xuICAgICAgICByZXR1cm4gYWNjO1xuICAgIH0sIHt9KTtcblxuICAgIGRlbGV0ZSByZXN1bHQuZGF0YTtcbiAgICBkZWxldGUgcmVzdWx0LnRvcGljcztcblxuICAgIHJldHVybiByZXN1bHQ7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGNyZWF0ZSBuZXcgZmlsdGVyIG9iamVjdCBmcm9tIGV2ZW50XG4gKlxuICogQG1ldGhvZCBleGVjdXRlXG4gKiBAcGFyYW0ge09iamVjdH0gaW5kZXhlZFxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnNcbiAqIEByZXR1cm4ge09iamVjdH0gZmlsdGVyIG9iamVjdFxuICovXG5Tb2xpZGl0eUV2ZW50LnByb3RvdHlwZS5leGVjdXRlID0gZnVuY3Rpb24gKGluZGV4ZWQsIG9wdGlvbnMpIHtcbiAgICB2YXIgbyA9IHRoaXMuZW5jb2RlKGluZGV4ZWQsIG9wdGlvbnMpO1xuICAgIHZhciBmb3JtYXR0ZXIgPSB0aGlzLmRlY29kZS5iaW5kKHRoaXMpO1xuICAgIHJldHVybiB3ZWIzLmV0aC5maWx0ZXIobywgdW5kZWZpbmVkLCB1bmRlZmluZWQsIGZvcm1hdHRlcik7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGF0dGFjaCBldmVudCB0byBjb250cmFjdCBvYmplY3RcbiAqXG4gKiBAbWV0aG9kIGF0dGFjaFRvQ29udHJhY3RcbiAqIEBwYXJhbSB7Q29udHJhY3R9XG4gKi9cblNvbGlkaXR5RXZlbnQucHJvdG90eXBlLmF0dGFjaFRvQ29udHJhY3QgPSBmdW5jdGlvbiAoY29udHJhY3QpIHtcbiAgICB2YXIgZXhlY3V0ZSA9IHRoaXMuZXhlY3V0ZS5iaW5kKHRoaXMpO1xuICAgIHZhciBkaXNwbGF5TmFtZSA9IHRoaXMuZGlzcGxheU5hbWUoKTtcbiAgICBpZiAoIWNvbnRyYWN0W2Rpc3BsYXlOYW1lXSkge1xuICAgICAgICBjb250cmFjdFtkaXNwbGF5TmFtZV0gPSBleGVjdXRlO1xuICAgIH1cbiAgICBjb250cmFjdFtkaXNwbGF5TmFtZV1bdGhpcy50eXBlTmFtZSgpXSA9IHRoaXMuZXhlY3V0ZS5iaW5kKHRoaXMsIGNvbnRyYWN0KTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gU29saWRpdHlFdmVudDtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogQGZpbGUgZmlsdGVyLmpzXG4gKiBAYXV0aG9yczpcbiAqICAgSmVmZnJleSBXaWxja2UgPGplZmZAZXRoZGV2LmNvbT5cbiAqICAgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiAgIE1hcmlhbiBPYW5jZWEgPG1hcmlhbkBldGhkZXYuY29tPlxuICogICBGYWJpYW4gVm9nZWxzdGVsbGVyIDxmYWJpYW5AZXRoZGV2LmNvbT5cbiAqICAgR2F2IFdvb2QgPGdAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTRcbiAqL1xuXG52YXIgUmVxdWVzdE1hbmFnZXIgPSByZXF1aXJlKCcuL3JlcXVlc3RtYW5hZ2VyJyk7XG52YXIgZm9ybWF0dGVycyA9IHJlcXVpcmUoJy4vZm9ybWF0dGVycycpO1xudmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMvdXRpbHMnKTtcblxuLyoqXG4qIENvbnZlcnRzIGEgZ2l2ZW4gdG9waWMgdG8gYSBoZXggc3RyaW5nLCBidXQgYWxzbyBhbGxvd3MgbnVsbCB2YWx1ZXMuXG4qXG4qIEBwYXJhbSB7TWl4ZWR9IHZhbHVlXG4qIEByZXR1cm4ge1N0cmluZ31cbiovXG52YXIgdG9Ub3BpYyA9IGZ1bmN0aW9uKHZhbHVlKXtcblxuICAgIGlmKHZhbHVlID09PSBudWxsIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpXG4gICAgICAgIHJldHVybiBudWxsO1xuXG4gICAgdmFsdWUgPSBTdHJpbmcodmFsdWUpO1xuXG4gICAgaWYodmFsdWUuaW5kZXhPZignMHgnKSA9PT0gMClcbiAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIGVsc2VcbiAgICAgICAgcmV0dXJuIHV0aWxzLmZyb21Bc2NpaSh2YWx1ZSk7XG59O1xuXG4vLy8gVGhpcyBtZXRob2Qgc2hvdWxkIGJlIGNhbGxlZCBvbiBvcHRpb25zIG9iamVjdCwgdG8gdmVyaWZ5IGRlcHJlY2F0ZWQgcHJvcGVydGllcyAmJiBsYXp5IGxvYWQgZHluYW1pYyBvbmVzXG4vLy8gQHBhcmFtIHNob3VsZCBiZSBzdHJpbmcgb3Igb2JqZWN0XG4vLy8gQHJldHVybnMgb3B0aW9ucyBzdHJpbmcgb3Igb2JqZWN0XG52YXIgZ2V0T3B0aW9ucyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG5cbiAgICBpZiAodXRpbHMuaXNTdHJpbmcob3B0aW9ucykpIHtcbiAgICAgICAgcmV0dXJuIG9wdGlvbnM7XG4gICAgfSBcblxuICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG4gICAgLy8gbWFrZSBzdXJlIHRvcGljcywgZ2V0IGNvbnZlcnRlZCB0byBoZXhcbiAgICBvcHRpb25zLnRvcGljcyA9IG9wdGlvbnMudG9waWNzIHx8IFtdO1xuICAgIG9wdGlvbnMudG9waWNzID0gb3B0aW9ucy50b3BpY3MubWFwKGZ1bmN0aW9uKHRvcGljKXtcbiAgICAgICAgcmV0dXJuICh1dGlscy5pc0FycmF5KHRvcGljKSkgPyB0b3BpYy5tYXAodG9Ub3BpYykgOiB0b1RvcGljKHRvcGljKTtcbiAgICB9KTtcblxuICAgIC8vIGxhenkgbG9hZFxuICAgIHJldHVybiB7XG4gICAgICAgIHRvcGljczogb3B0aW9ucy50b3BpY3MsXG4gICAgICAgIHRvOiBvcHRpb25zLnRvLFxuICAgICAgICBhZGRyZXNzOiBvcHRpb25zLmFkZHJlc3MsXG4gICAgICAgIGZyb21CbG9jazogZm9ybWF0dGVycy5pbnB1dEJsb2NrTnVtYmVyRm9ybWF0dGVyKG9wdGlvbnMuZnJvbUJsb2NrKSxcbiAgICAgICAgdG9CbG9jazogZm9ybWF0dGVycy5pbnB1dEJsb2NrTnVtYmVyRm9ybWF0dGVyKG9wdGlvbnMudG9CbG9jaykgXG4gICAgfTsgXG59O1xuXG52YXIgRmlsdGVyID0gZnVuY3Rpb24gKG9wdGlvbnMsIG1ldGhvZHMsIGZvcm1hdHRlcikge1xuICAgIHZhciBpbXBsZW1lbnRhdGlvbiA9IHt9O1xuICAgIG1ldGhvZHMuZm9yRWFjaChmdW5jdGlvbiAobWV0aG9kKSB7XG4gICAgICAgIG1ldGhvZC5hdHRhY2hUb09iamVjdChpbXBsZW1lbnRhdGlvbik7XG4gICAgfSk7XG4gICAgdGhpcy5vcHRpb25zID0gZ2V0T3B0aW9ucyhvcHRpb25zKTtcbiAgICB0aGlzLmltcGxlbWVudGF0aW9uID0gaW1wbGVtZW50YXRpb247XG4gICAgdGhpcy5jYWxsYmFja3MgPSBbXTtcbiAgICB0aGlzLmZvcm1hdHRlciA9IGZvcm1hdHRlcjtcbiAgICB0aGlzLmZpbHRlcklkID0gdGhpcy5pbXBsZW1lbnRhdGlvbi5uZXdGaWx0ZXIodGhpcy5vcHRpb25zKTtcbn07XG5cbkZpbHRlci5wcm90b3R5cGUud2F0Y2ggPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgICB0aGlzLmNhbGxiYWNrcy5wdXNoKGNhbGxiYWNrKTtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgICB2YXIgb25NZXNzYWdlID0gZnVuY3Rpb24gKGVycm9yLCBtZXNzYWdlcykge1xuICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgIHJldHVybiBzZWxmLmNhbGxiYWNrcy5mb3JFYWNoKGZ1bmN0aW9uIChjYWxsYmFjaykge1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKGVycm9yKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgbWVzc2FnZXMuZm9yRWFjaChmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAgICAgbWVzc2FnZSA9IHNlbGYuZm9ybWF0dGVyID8gc2VsZi5mb3JtYXR0ZXIobWVzc2FnZSkgOiBtZXNzYWdlO1xuICAgICAgICAgICAgc2VsZi5jYWxsYmFja3MuZm9yRWFjaChmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICBjYWxsYmFjayhudWxsLCBtZXNzYWdlKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgLy8gY2FsbCBnZXRGaWx0ZXJMb2dzIG9uIHN0YXJ0XG4gICAgaWYgKCF1dGlscy5pc1N0cmluZyh0aGlzLm9wdGlvbnMpKSB7XG4gICAgICAgIHRoaXMuZ2V0KGZ1bmN0aW9uIChlcnIsIG1lc3NhZ2VzKSB7XG4gICAgICAgICAgICAvLyBkb24ndCBzZW5kIGFsbCB0aGUgcmVzcG9uc2VzIHRvIGFsbCB0aGUgd2F0Y2hlcyBhZ2Fpbi4uLiBqdXN0IHRvIHRoaXMgb25lXG4gICAgICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2soZXJyKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbWVzc2FnZXMuZm9yRWFjaChmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKG51bGwsIG1lc3NhZ2UpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIFJlcXVlc3RNYW5hZ2VyLmdldEluc3RhbmNlKCkuc3RhcnRQb2xsaW5nKHtcbiAgICAgICAgbWV0aG9kOiB0aGlzLmltcGxlbWVudGF0aW9uLnBvbGwuY2FsbCxcbiAgICAgICAgcGFyYW1zOiBbdGhpcy5maWx0ZXJJZF0sXG4gICAgfSwgdGhpcy5maWx0ZXJJZCwgb25NZXNzYWdlLCB0aGlzLnN0b3BXYXRjaGluZy5iaW5kKHRoaXMpKTtcbn07XG5cbkZpbHRlci5wcm90b3R5cGUuc3RvcFdhdGNoaW5nID0gZnVuY3Rpb24gKCkge1xuICAgIFJlcXVlc3RNYW5hZ2VyLmdldEluc3RhbmNlKCkuc3RvcFBvbGxpbmcodGhpcy5maWx0ZXJJZCk7XG4gICAgdGhpcy5pbXBsZW1lbnRhdGlvbi51bmluc3RhbGxGaWx0ZXIodGhpcy5maWx0ZXJJZCk7XG4gICAgdGhpcy5jYWxsYmFja3MgPSBbXTtcbn07XG5cbkZpbHRlci5wcm90b3R5cGUuZ2V0ID0gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIGlmICh1dGlscy5pc0Z1bmN0aW9uKGNhbGxiYWNrKSkge1xuICAgICAgICB0aGlzLmltcGxlbWVudGF0aW9uLmdldExvZ3ModGhpcy5maWx0ZXJJZCwgZnVuY3Rpb24oZXJyLCByZXMpe1xuICAgICAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKGVycik7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrKG51bGwsIHJlcy5tYXAoZnVuY3Rpb24gKGxvZykge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gc2VsZi5mb3JtYXR0ZXIgPyBzZWxmLmZvcm1hdHRlcihsb2cpIDogbG9nO1xuICAgICAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdmFyIGxvZ3MgPSB0aGlzLmltcGxlbWVudGF0aW9uLmdldExvZ3ModGhpcy5maWx0ZXJJZCk7XG4gICAgICAgIHJldHVybiBsb2dzLm1hcChmdW5jdGlvbiAobG9nKSB7XG4gICAgICAgICAgICByZXR1cm4gc2VsZi5mb3JtYXR0ZXIgPyBzZWxmLmZvcm1hdHRlcihsb2cpIDogbG9nO1xuICAgICAgICB9KTtcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEZpbHRlcjtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogXG4gKiBAZmlsZSBmb3JtYXR0ZXJzLmpzXG4gKiBAYXV0aG9yIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGF1dGhvciBGYWJpYW4gVm9nZWxzdGVsbGVyIDxmYWJpYW5AZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy91dGlscycpO1xudmFyIGNvbmZpZyA9IHJlcXVpcmUoJy4uL3V0aWxzL2NvbmZpZycpO1xuXG4vKipcbiAqIFNob3VsZCB0aGUgZm9ybWF0IG91dHB1dCB0byBhIGJpZyBudW1iZXJcbiAqXG4gKiBAbWV0aG9kIG91dHB1dEJpZ051bWJlckZvcm1hdHRlclxuICogQHBhcmFtIHtTdHJpbmd8TnVtYmVyfEJpZ051bWJlcn1cbiAqIEByZXR1cm5zIHtCaWdOdW1iZXJ9IG9iamVjdFxuICovXG52YXIgb3V0cHV0QmlnTnVtYmVyRm9ybWF0dGVyID0gZnVuY3Rpb24gKG51bWJlcikge1xuICAgIHJldHVybiB1dGlscy50b0JpZ051bWJlcihudW1iZXIpO1xufTtcblxudmFyIGlzUHJlZGVmaW5lZEJsb2NrTnVtYmVyID0gZnVuY3Rpb24gKGJsb2NrTnVtYmVyKSB7XG4gICAgcmV0dXJuIGJsb2NrTnVtYmVyID09PSAnbGF0ZXN0JyB8fCBibG9ja051bWJlciA9PT0gJ3BlbmRpbmcnIHx8IGJsb2NrTnVtYmVyID09PSAnZWFybGllc3QnO1xufTtcblxudmFyIGlucHV0RGVmYXVsdEJsb2NrTnVtYmVyRm9ybWF0dGVyID0gZnVuY3Rpb24gKGJsb2NrTnVtYmVyKSB7XG4gICAgaWYgKGJsb2NrTnVtYmVyID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgcmV0dXJuIGNvbmZpZy5kZWZhdWx0QmxvY2s7XG4gICAgfVxuICAgIHJldHVybiBpbnB1dEJsb2NrTnVtYmVyRm9ybWF0dGVyKGJsb2NrTnVtYmVyKTtcbn07XG5cbnZhciBpbnB1dEJsb2NrTnVtYmVyRm9ybWF0dGVyID0gZnVuY3Rpb24gKGJsb2NrTnVtYmVyKSB7XG4gICAgaWYgKGJsb2NrTnVtYmVyID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9IGVsc2UgaWYgKGlzUHJlZGVmaW5lZEJsb2NrTnVtYmVyKGJsb2NrTnVtYmVyKSkge1xuICAgICAgICByZXR1cm4gYmxvY2tOdW1iZXI7XG4gICAgfVxuICAgIHJldHVybiB1dGlscy50b0hleChibG9ja051bWJlcik7XG59O1xuXG4vKipcbiAqIEZvcm1hdHMgdGhlIGlucHV0IG9mIGEgdHJhbnNhY3Rpb24gYW5kIGNvbnZlcnRzIGFsbCB2YWx1ZXMgdG8gSEVYXG4gKlxuICogQG1ldGhvZCBpbnB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyXG4gKiBAcGFyYW0ge09iamVjdH0gdHJhbnNhY3Rpb24gb3B0aW9uc1xuICogQHJldHVybnMgb2JqZWN0XG4qL1xudmFyIGlucHV0VHJhbnNhY3Rpb25Gb3JtYXR0ZXIgPSBmdW5jdGlvbiAob3B0aW9ucyl7XG5cbiAgICBvcHRpb25zLmZyb20gPSBvcHRpb25zLmZyb20gfHwgY29uZmlnLmRlZmF1bHRBY2NvdW50O1xuXG4gICAgLy8gbWFrZSBjb2RlIC0+IGRhdGFcbiAgICBpZiAob3B0aW9ucy5jb2RlKSB7XG4gICAgICAgIG9wdGlvbnMuZGF0YSA9IG9wdGlvbnMuY29kZTtcbiAgICAgICAgZGVsZXRlIG9wdGlvbnMuY29kZTtcbiAgICB9XG5cbiAgICBbJ2dhc1ByaWNlJywgJ2dhcycsICd2YWx1ZScsICdub25jZSddLmZpbHRlcihmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgIHJldHVybiBvcHRpb25zW2tleV0gIT09IHVuZGVmaW5lZDtcbiAgICB9KS5mb3JFYWNoKGZ1bmN0aW9uKGtleSl7XG4gICAgICAgIG9wdGlvbnNba2V5XSA9IHV0aWxzLmZyb21EZWNpbWFsKG9wdGlvbnNba2V5XSk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gb3B0aW9uczsgXG59O1xuXG4vKipcbiAqIEZvcm1hdHMgdGhlIG91dHB1dCBvZiBhIHRyYW5zYWN0aW9uIHRvIGl0cyBwcm9wZXIgdmFsdWVzXG4gKiBcbiAqIEBtZXRob2Qgb3V0cHV0VHJhbnNhY3Rpb25Gb3JtYXR0ZXJcbiAqIEBwYXJhbSB7T2JqZWN0fSB0cmFuc2FjdGlvblxuICogQHJldHVybnMge09iamVjdH0gdHJhbnNhY3Rpb25cbiovXG52YXIgb3V0cHV0VHJhbnNhY3Rpb25Gb3JtYXR0ZXIgPSBmdW5jdGlvbiAodHgpe1xuICAgIHR4LmJsb2NrTnVtYmVyID0gdXRpbHMudG9EZWNpbWFsKHR4LmJsb2NrTnVtYmVyKTtcbiAgICB0eC50cmFuc2FjdGlvbkluZGV4ID0gdXRpbHMudG9EZWNpbWFsKHR4LnRyYW5zYWN0aW9uSW5kZXgpO1xuICAgIHR4Lm5vbmNlID0gdXRpbHMudG9EZWNpbWFsKHR4Lm5vbmNlKTtcbiAgICB0eC5nYXMgPSB1dGlscy50b0RlY2ltYWwodHguZ2FzKTtcbiAgICB0eC5nYXNQcmljZSA9IHV0aWxzLnRvQmlnTnVtYmVyKHR4Lmdhc1ByaWNlKTtcbiAgICB0eC52YWx1ZSA9IHV0aWxzLnRvQmlnTnVtYmVyKHR4LnZhbHVlKTtcbiAgICByZXR1cm4gdHg7XG59O1xuXG4vKipcbiAqIEZvcm1hdHMgdGhlIG91dHB1dCBvZiBhIGJsb2NrIHRvIGl0cyBwcm9wZXIgdmFsdWVzXG4gKlxuICogQG1ldGhvZCBvdXRwdXRCbG9ja0Zvcm1hdHRlclxuICogQHBhcmFtIHtPYmplY3R9IGJsb2NrIG9iamVjdCBcbiAqIEByZXR1cm5zIHtPYmplY3R9IGJsb2NrIG9iamVjdFxuKi9cbnZhciBvdXRwdXRCbG9ja0Zvcm1hdHRlciA9IGZ1bmN0aW9uKGJsb2NrKSB7XG5cbiAgICAvLyB0cmFuc2Zvcm0gdG8gbnVtYmVyXG4gICAgYmxvY2suZ2FzTGltaXQgPSB1dGlscy50b0RlY2ltYWwoYmxvY2suZ2FzTGltaXQpO1xuICAgIGJsb2NrLmdhc1VzZWQgPSB1dGlscy50b0RlY2ltYWwoYmxvY2suZ2FzVXNlZCk7XG4gICAgYmxvY2suc2l6ZSA9IHV0aWxzLnRvRGVjaW1hbChibG9jay5zaXplKTtcbiAgICBibG9jay50aW1lc3RhbXAgPSB1dGlscy50b0RlY2ltYWwoYmxvY2sudGltZXN0YW1wKTtcbiAgICBibG9jay5udW1iZXIgPSB1dGlscy50b0RlY2ltYWwoYmxvY2subnVtYmVyKTtcblxuICAgIGJsb2NrLmRpZmZpY3VsdHkgPSB1dGlscy50b0JpZ051bWJlcihibG9jay5kaWZmaWN1bHR5KTtcbiAgICBibG9jay50b3RhbERpZmZpY3VsdHkgPSB1dGlscy50b0JpZ051bWJlcihibG9jay50b3RhbERpZmZpY3VsdHkpO1xuXG4gICAgaWYgKHV0aWxzLmlzQXJyYXkoYmxvY2sudHJhbnNhY3Rpb25zKSkge1xuICAgICAgICBibG9jay50cmFuc2FjdGlvbnMuZm9yRWFjaChmdW5jdGlvbihpdGVtKXtcbiAgICAgICAgICAgIGlmKCF1dGlscy5pc1N0cmluZyhpdGVtKSlcbiAgICAgICAgICAgICAgICByZXR1cm4gb3V0cHV0VHJhbnNhY3Rpb25Gb3JtYXR0ZXIoaXRlbSk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiBibG9jaztcbn07XG5cbi8qKlxuICogRm9ybWF0cyB0aGUgb3V0cHV0IG9mIGEgbG9nXG4gKiBcbiAqIEBtZXRob2Qgb3V0cHV0TG9nRm9ybWF0dGVyXG4gKiBAcGFyYW0ge09iamVjdH0gbG9nIG9iamVjdFxuICogQHJldHVybnMge09iamVjdH0gbG9nXG4qL1xudmFyIG91dHB1dExvZ0Zvcm1hdHRlciA9IGZ1bmN0aW9uKGxvZykge1xuICAgIGlmIChsb2cgPT09IG51bGwpIHsgLy8gJ3BlbmRpbmcnICYmICdsYXRlc3QnIGZpbHRlcnMgYXJlIG51bGxzXG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGxvZy5ibG9ja051bWJlciA9IHV0aWxzLnRvRGVjaW1hbChsb2cuYmxvY2tOdW1iZXIpO1xuICAgIGxvZy50cmFuc2FjdGlvbkluZGV4ID0gdXRpbHMudG9EZWNpbWFsKGxvZy50cmFuc2FjdGlvbkluZGV4KTtcbiAgICBsb2cubG9nSW5kZXggPSB1dGlscy50b0RlY2ltYWwobG9nLmxvZ0luZGV4KTtcblxuICAgIHJldHVybiBsb2c7XG59O1xuXG4vKipcbiAqIEZvcm1hdHMgdGhlIGlucHV0IG9mIGEgd2hpc3BlciBwb3N0IGFuZCBjb252ZXJ0cyBhbGwgdmFsdWVzIHRvIEhFWFxuICpcbiAqIEBtZXRob2QgaW5wdXRQb3N0Rm9ybWF0dGVyXG4gKiBAcGFyYW0ge09iamVjdH0gdHJhbnNhY3Rpb24gb2JqZWN0XG4gKiBAcmV0dXJucyB7T2JqZWN0fVxuKi9cbnZhciBpbnB1dFBvc3RGb3JtYXR0ZXIgPSBmdW5jdGlvbihwb3N0KSB7XG5cbiAgICBwb3N0LnBheWxvYWQgPSB1dGlscy50b0hleChwb3N0LnBheWxvYWQpO1xuICAgIHBvc3QudHRsID0gdXRpbHMuZnJvbURlY2ltYWwocG9zdC50dGwpO1xuICAgIHBvc3Qud29ya1RvUHJvdmUgPSB1dGlscy5mcm9tRGVjaW1hbChwb3N0LndvcmtUb1Byb3ZlKTtcbiAgICBwb3N0LnByaW9yaXR5ID0gdXRpbHMuZnJvbURlY2ltYWwocG9zdC5wcmlvcml0eSk7XG5cbiAgICAvLyBmYWxsYmFja1xuICAgIGlmICghdXRpbHMuaXNBcnJheShwb3N0LnRvcGljcykpIHtcbiAgICAgICAgcG9zdC50b3BpY3MgPSBwb3N0LnRvcGljcyA/IFtwb3N0LnRvcGljc10gOiBbXTtcbiAgICB9XG5cbiAgICAvLyBmb3JtYXQgdGhlIGZvbGxvd2luZyBvcHRpb25zXG4gICAgcG9zdC50b3BpY3MgPSBwb3N0LnRvcGljcy5tYXAoZnVuY3Rpb24odG9waWMpe1xuICAgICAgICByZXR1cm4gdXRpbHMuZnJvbUFzY2lpKHRvcGljKTtcbiAgICB9KTtcblxuICAgIHJldHVybiBwb3N0OyBcbn07XG5cbi8qKlxuICogRm9ybWF0cyB0aGUgb3V0cHV0IG9mIGEgcmVjZWl2ZWQgcG9zdCBtZXNzYWdlXG4gKlxuICogQG1ldGhvZCBvdXRwdXRQb3N0Rm9ybWF0dGVyXG4gKiBAcGFyYW0ge09iamVjdH1cbiAqIEByZXR1cm5zIHtPYmplY3R9XG4gKi9cbnZhciBvdXRwdXRQb3N0Rm9ybWF0dGVyID0gZnVuY3Rpb24ocG9zdCl7XG5cbiAgICBwb3N0LmV4cGlyeSA9IHV0aWxzLnRvRGVjaW1hbChwb3N0LmV4cGlyeSk7XG4gICAgcG9zdC5zZW50ID0gdXRpbHMudG9EZWNpbWFsKHBvc3Quc2VudCk7XG4gICAgcG9zdC50dGwgPSB1dGlscy50b0RlY2ltYWwocG9zdC50dGwpO1xuICAgIHBvc3Qud29ya1Byb3ZlZCA9IHV0aWxzLnRvRGVjaW1hbChwb3N0LndvcmtQcm92ZWQpO1xuICAgIHBvc3QucGF5bG9hZFJhdyA9IHBvc3QucGF5bG9hZDtcbiAgICBwb3N0LnBheWxvYWQgPSB1dGlscy50b0FzY2lpKHBvc3QucGF5bG9hZCk7XG5cbiAgICBpZiAodXRpbHMuaXNKc29uKHBvc3QucGF5bG9hZCkpIHtcbiAgICAgICAgcG9zdC5wYXlsb2FkID0gSlNPTi5wYXJzZShwb3N0LnBheWxvYWQpO1xuICAgIH1cblxuICAgIC8vIGZvcm1hdCB0aGUgZm9sbG93aW5nIG9wdGlvbnNcbiAgICBpZiAoIXBvc3QudG9waWNzKSB7XG4gICAgICAgIHBvc3QudG9waWNzID0gW107XG4gICAgfVxuICAgIHBvc3QudG9waWNzID0gcG9zdC50b3BpY3MubWFwKGZ1bmN0aW9uKHRvcGljKXtcbiAgICAgICAgcmV0dXJuIHV0aWxzLnRvQXNjaWkodG9waWMpO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIHBvc3Q7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBpbnB1dERlZmF1bHRCbG9ja051bWJlckZvcm1hdHRlcjogaW5wdXREZWZhdWx0QmxvY2tOdW1iZXJGb3JtYXR0ZXIsXG4gICAgaW5wdXRCbG9ja051bWJlckZvcm1hdHRlcjogaW5wdXRCbG9ja051bWJlckZvcm1hdHRlcixcbiAgICBpbnB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyOiBpbnB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyLFxuICAgIGlucHV0UG9zdEZvcm1hdHRlcjogaW5wdXRQb3N0Rm9ybWF0dGVyLFxuICAgIG91dHB1dEJpZ051bWJlckZvcm1hdHRlcjogb3V0cHV0QmlnTnVtYmVyRm9ybWF0dGVyLFxuICAgIG91dHB1dFRyYW5zYWN0aW9uRm9ybWF0dGVyOiBvdXRwdXRUcmFuc2FjdGlvbkZvcm1hdHRlcixcbiAgICBvdXRwdXRCbG9ja0Zvcm1hdHRlcjogb3V0cHV0QmxvY2tGb3JtYXR0ZXIsXG4gICAgb3V0cHV0TG9nRm9ybWF0dGVyOiBvdXRwdXRMb2dGb3JtYXR0ZXIsXG4gICAgb3V0cHV0UG9zdEZvcm1hdHRlcjogb3V0cHV0UG9zdEZvcm1hdHRlclxufTtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKipcbiAqIEBmaWxlIGZ1bmN0aW9uLmpzXG4gKiBAYXV0aG9yIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbnZhciB3ZWIzID0gcmVxdWlyZSgnLi4vd2ViMycpO1xudmFyIGNvZGVyID0gcmVxdWlyZSgnLi4vc29saWRpdHkvY29kZXInKTtcbnZhciB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzL3V0aWxzJyk7XG52YXIgc2hhMyA9IHJlcXVpcmUoJy4uL3V0aWxzL3NoYTMnKTtcblxuLyoqXG4gKiBUaGlzIHByb3RvdHlwZSBzaG91bGQgYmUgdXNlZCB0byBjYWxsL3NlbmRUcmFuc2FjdGlvbiB0byBzb2xpZGl0eSBmdW5jdGlvbnNcbiAqL1xudmFyIFNvbGlkaXR5RnVuY3Rpb24gPSBmdW5jdGlvbiAoanNvbiwgYWRkcmVzcykge1xuICAgIHRoaXMuX2lucHV0VHlwZXMgPSBqc29uLmlucHV0cy5tYXAoZnVuY3Rpb24gKGkpIHtcbiAgICAgICAgcmV0dXJuIGkudHlwZTtcbiAgICB9KTtcbiAgICB0aGlzLl9vdXRwdXRUeXBlcyA9IGpzb24ub3V0cHV0cy5tYXAoZnVuY3Rpb24gKGkpIHtcbiAgICAgICAgcmV0dXJuIGkudHlwZTtcbiAgICB9KTtcbiAgICB0aGlzLl9jb25zdGFudCA9IGpzb24uY29uc3RhbnQ7XG4gICAgdGhpcy5fbmFtZSA9IHV0aWxzLnRyYW5zZm9ybVRvRnVsbE5hbWUoanNvbik7XG4gICAgdGhpcy5fYWRkcmVzcyA9IGFkZHJlc3M7XG59O1xuXG5Tb2xpZGl0eUZ1bmN0aW9uLnByb3RvdHlwZS5leHRyYWN0Q2FsbGJhY2sgPSBmdW5jdGlvbiAoYXJncykge1xuICAgIGlmICh1dGlscy5pc0Z1bmN0aW9uKGFyZ3NbYXJncy5sZW5ndGggLSAxXSkpIHtcbiAgICAgICAgcmV0dXJuIGFyZ3MucG9wKCk7IC8vIG1vZGlmeSB0aGUgYXJncyBhcnJheSFcbiAgICB9XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGNyZWF0ZSBwYXlsb2FkIGZyb20gYXJndW1lbnRzXG4gKlxuICogQG1ldGhvZCB0b1BheWxvYWRcbiAqIEBwYXJhbSB7QXJyYXl9IHNvbGlkaXR5IGZ1bmN0aW9uIHBhcmFtc1xuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbmFsIHBheWxvYWQgb3B0aW9uc1xuICovXG5Tb2xpZGl0eUZ1bmN0aW9uLnByb3RvdHlwZS50b1BheWxvYWQgPSBmdW5jdGlvbiAoYXJncykge1xuICAgIHZhciBvcHRpb25zID0ge307XG4gICAgaWYgKGFyZ3MubGVuZ3RoID4gdGhpcy5faW5wdXRUeXBlcy5sZW5ndGggJiYgdXRpbHMuaXNPYmplY3QoYXJnc1thcmdzLmxlbmd0aCAtMV0pKSB7XG4gICAgICAgIG9wdGlvbnMgPSBhcmdzW2FyZ3MubGVuZ3RoIC0gMV07XG4gICAgfVxuICAgIG9wdGlvbnMudG8gPSB0aGlzLl9hZGRyZXNzO1xuICAgIG9wdGlvbnMuZGF0YSA9ICcweCcgKyB0aGlzLnNpZ25hdHVyZSgpICsgY29kZXIuZW5jb2RlUGFyYW1zKHRoaXMuX2lucHV0VHlwZXMsIGFyZ3MpO1xuICAgIHJldHVybiBvcHRpb25zO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBnZXQgZnVuY3Rpb24gc2lnbmF0dXJlXG4gKlxuICogQG1ldGhvZCBzaWduYXR1cmVcbiAqIEByZXR1cm4ge1N0cmluZ30gZnVuY3Rpb24gc2lnbmF0dXJlXG4gKi9cblNvbGlkaXR5RnVuY3Rpb24ucHJvdG90eXBlLnNpZ25hdHVyZSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gc2hhMyh0aGlzLl9uYW1lKS5zbGljZSgwLCA4KTtcbn07XG5cblxuU29saWRpdHlGdW5jdGlvbi5wcm90b3R5cGUudW5wYWNrT3V0cHV0ID0gZnVuY3Rpb24gKG91dHB1dCkge1xuICAgIGlmICghb3V0cHV0KSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBvdXRwdXQgPSBvdXRwdXQubGVuZ3RoID49IDIgPyBvdXRwdXQuc2xpY2UoMikgOiBvdXRwdXQ7XG4gICAgdmFyIHJlc3VsdCA9IGNvZGVyLmRlY29kZVBhcmFtcyh0aGlzLl9vdXRwdXRUeXBlcywgb3V0cHV0KTtcbiAgICByZXR1cm4gcmVzdWx0Lmxlbmd0aCA9PT0gMSA/IHJlc3VsdFswXSA6IHJlc3VsdDtcbn07XG5cbi8qKlxuICogQ2FsbHMgYSBjb250cmFjdCBmdW5jdGlvbi5cbiAqXG4gKiBAbWV0aG9kIGNhbGxcbiAqIEBwYXJhbSB7Li4uT2JqZWN0fSBDb250cmFjdCBmdW5jdGlvbiBhcmd1bWVudHNcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IElmIHRoZSBsYXN0IGFyZ3VtZW50IGlzIGEgZnVuY3Rpb24sIHRoZSBjb250cmFjdCBmdW5jdGlvblxuICogICBjYWxsIHdpbGwgYmUgYXN5bmNocm9ub3VzLCBhbmQgdGhlIGNhbGxiYWNrIHdpbGwgYmUgcGFzc2VkIHRoZVxuICogICBlcnJvciBhbmQgcmVzdWx0LlxuICogQHJldHVybiB7U3RyaW5nfSBvdXRwdXQgYnl0ZXNcbiAqL1xuU29saWRpdHlGdW5jdGlvbi5wcm90b3R5cGUuY2FsbCA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cykuZmlsdGVyKGZ1bmN0aW9uIChhKSB7cmV0dXJuIGEgIT09IHVuZGVmaW5lZDsgfSk7XG4gICAgdmFyIGNhbGxiYWNrID0gdGhpcy5leHRyYWN0Q2FsbGJhY2soYXJncyk7XG4gICAgdmFyIHBheWxvYWQgPSB0aGlzLnRvUGF5bG9hZChhcmdzKTtcblxuICAgIGlmICghY2FsbGJhY2spIHtcbiAgICAgICAgdmFyIG91dHB1dCA9IHdlYjMuZXRoLmNhbGwocGF5bG9hZCk7XG4gICAgICAgIHJldHVybiB0aGlzLnVucGFja091dHB1dChvdXRwdXQpO1xuICAgIH0gXG4gICAgICAgIFxuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB3ZWIzLmV0aC5jYWxsKHBheWxvYWQsIGZ1bmN0aW9uIChlcnJvciwgb3V0cHV0KSB7XG4gICAgICAgIGNhbGxiYWNrKGVycm9yLCBzZWxmLnVucGFja091dHB1dChvdXRwdXQpKTtcbiAgICB9KTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gc2VuZFRyYW5zYWN0aW9uIHRvIHNvbGlkaXR5IGZ1bmN0aW9uXG4gKlxuICogQG1ldGhvZCBzZW5kVHJhbnNhY3Rpb25cbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zXG4gKi9cblNvbGlkaXR5RnVuY3Rpb24ucHJvdG90eXBlLnNlbmRUcmFuc2FjdGlvbiA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cykuZmlsdGVyKGZ1bmN0aW9uIChhKSB7cmV0dXJuIGEgIT09IHVuZGVmaW5lZDsgfSk7XG4gICAgdmFyIGNhbGxiYWNrID0gdGhpcy5leHRyYWN0Q2FsbGJhY2soYXJncyk7XG4gICAgdmFyIHBheWxvYWQgPSB0aGlzLnRvUGF5bG9hZChhcmdzKTtcblxuICAgIGlmICghY2FsbGJhY2spIHtcbiAgICAgICAgcmV0dXJuIHdlYjMuZXRoLnNlbmRUcmFuc2FjdGlvbihwYXlsb2FkKTtcbiAgICB9XG5cbiAgICB3ZWIzLmV0aC5zZW5kVHJhbnNhY3Rpb24ocGF5bG9hZCwgY2FsbGJhY2spO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBlc3RpbWF0ZUdhcyBvZiBzb2xpZGl0eSBmdW5jdGlvblxuICpcbiAqIEBtZXRob2QgZXN0aW1hdGVHYXNcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zXG4gKi9cblNvbGlkaXR5RnVuY3Rpb24ucHJvdG90eXBlLmVzdGltYXRlR2FzID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKTtcbiAgICB2YXIgY2FsbGJhY2sgPSB0aGlzLmV4dHJhY3RDYWxsYmFjayhhcmdzKTtcbiAgICB2YXIgcGF5bG9hZCA9IHRoaXMudG9QYXlsb2FkKGFyZ3MpO1xuXG4gICAgaWYgKCFjYWxsYmFjaykge1xuICAgICAgICByZXR1cm4gd2ViMy5ldGguZXN0aW1hdGVHYXMocGF5bG9hZCk7XG4gICAgfVxuXG4gICAgd2ViMy5ldGguZXN0aW1hdGVHYXMocGF5bG9hZCwgY2FsbGJhY2spO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBnZXQgZnVuY3Rpb24gZGlzcGxheSBuYW1lXG4gKlxuICogQG1ldGhvZCBkaXNwbGF5TmFtZVxuICogQHJldHVybiB7U3RyaW5nfSBkaXNwbGF5IG5hbWUgb2YgdGhlIGZ1bmN0aW9uXG4gKi9cblNvbGlkaXR5RnVuY3Rpb24ucHJvdG90eXBlLmRpc3BsYXlOYW1lID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB1dGlscy5leHRyYWN0RGlzcGxheU5hbWUodGhpcy5fbmFtZSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGdldCBmdW5jdGlvbiB0eXBlIG5hbWVcbiAqXG4gKiBAbWV0aG9kIHR5cGVOYW1lXG4gKiBAcmV0dXJuIHtTdHJpbmd9IHR5cGUgbmFtZSBvZiB0aGUgZnVuY3Rpb25cbiAqL1xuU29saWRpdHlGdW5jdGlvbi5wcm90b3R5cGUudHlwZU5hbWUgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHV0aWxzLmV4dHJhY3RUeXBlTmFtZSh0aGlzLl9uYW1lKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBnZXQgcnBjIHJlcXVlc3RzIGZyb20gc29saWRpdHkgZnVuY3Rpb25cbiAqXG4gKiBAbWV0aG9kIHJlcXVlc3RcbiAqIEByZXR1cm5zIHtPYmplY3R9XG4gKi9cblNvbGlkaXR5RnVuY3Rpb24ucHJvdG90eXBlLnJlcXVlc3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuICAgIHZhciBjYWxsYmFjayA9IHRoaXMuZXh0cmFjdENhbGxiYWNrKGFyZ3MpO1xuICAgIHZhciBwYXlsb2FkID0gdGhpcy50b1BheWxvYWQoYXJncyk7XG4gICAgdmFyIGZvcm1hdCA9IHRoaXMudW5wYWNrT3V0cHV0LmJpbmQodGhpcyk7XG4gICAgXG4gICAgcmV0dXJuIHtcbiAgICAgICAgY2FsbGJhY2s6IGNhbGxiYWNrLFxuICAgICAgICBwYXlsb2FkOiBwYXlsb2FkLCBcbiAgICAgICAgZm9ybWF0OiBmb3JtYXRcbiAgICB9O1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGV4ZWN1dGUgZnVuY3Rpb25cbiAqXG4gKiBAbWV0aG9kIGV4ZWN1dGVcbiAqL1xuU29saWRpdHlGdW5jdGlvbi5wcm90b3R5cGUuZXhlY3V0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgdHJhbnNhY3Rpb24gPSAhdGhpcy5fY29uc3RhbnQ7XG5cbiAgICAvLyBzZW5kIHRyYW5zYWN0aW9uXG4gICAgaWYgKHRyYW5zYWN0aW9uKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnNlbmRUcmFuc2FjdGlvbi5hcHBseSh0aGlzLCBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpKTtcbiAgICB9XG5cbiAgICAvLyBjYWxsXG4gICAgcmV0dXJuIHRoaXMuY2FsbC5hcHBseSh0aGlzLCBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBhdHRhY2ggZnVuY3Rpb24gdG8gY29udHJhY3RcbiAqXG4gKiBAbWV0aG9kIGF0dGFjaFRvQ29udHJhY3RcbiAqIEBwYXJhbSB7Q29udHJhY3R9XG4gKi9cblNvbGlkaXR5RnVuY3Rpb24ucHJvdG90eXBlLmF0dGFjaFRvQ29udHJhY3QgPSBmdW5jdGlvbiAoY29udHJhY3QpIHtcbiAgICB2YXIgZXhlY3V0ZSA9IHRoaXMuZXhlY3V0ZS5iaW5kKHRoaXMpO1xuICAgIGV4ZWN1dGUucmVxdWVzdCA9IHRoaXMucmVxdWVzdC5iaW5kKHRoaXMpO1xuICAgIGV4ZWN1dGUuY2FsbCA9IHRoaXMuY2FsbC5iaW5kKHRoaXMpO1xuICAgIGV4ZWN1dGUuc2VuZFRyYW5zYWN0aW9uID0gdGhpcy5zZW5kVHJhbnNhY3Rpb24uYmluZCh0aGlzKTtcbiAgICBleGVjdXRlLmVzdGltYXRlR2FzID0gdGhpcy5lc3RpbWF0ZUdhcy5iaW5kKHRoaXMpO1xuICAgIHZhciBkaXNwbGF5TmFtZSA9IHRoaXMuZGlzcGxheU5hbWUoKTtcbiAgICBpZiAoIWNvbnRyYWN0W2Rpc3BsYXlOYW1lXSkge1xuICAgICAgICBjb250cmFjdFtkaXNwbGF5TmFtZV0gPSBleGVjdXRlO1xuICAgIH1cbiAgICBjb250cmFjdFtkaXNwbGF5TmFtZV1bdGhpcy50eXBlTmFtZSgpXSA9IGV4ZWN1dGU7IC8vIGNpcmN1bGFyISEhIVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTb2xpZGl0eUZ1bmN0aW9uO1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBAZmlsZSBodHRwcHJvdmlkZXIuanNcbiAqIEBhdXRob3JzOlxuICogICBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqICAgTWFyaWFuIE9hbmNlYSA8bWFyaWFuQGV0aGRldi5jb20+XG4gKiAgIEZhYmlhbiBWb2dlbHN0ZWxsZXIgPGZhYmlhbkBldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNFxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgWE1MSHR0cFJlcXVlc3QgPSByZXF1aXJlKCd4bWxodHRwcmVxdWVzdCcpLlhNTEh0dHBSZXF1ZXN0OyAvLyBqc2hpbnQgaWdub3JlOmxpbmVcbnZhciBlcnJvcnMgPSByZXF1aXJlKCcuL2Vycm9ycycpO1xuXG52YXIgSHR0cFByb3ZpZGVyID0gZnVuY3Rpb24gKGhvc3QpIHtcbiAgICB0aGlzLmhvc3QgPSBob3N0IHx8ICdodHRwOi8vbG9jYWxob3N0Ojg1NDUnO1xufTtcblxuSHR0cFByb3ZpZGVyLnByb3RvdHlwZS5zZW5kID0gZnVuY3Rpb24gKHBheWxvYWQpIHtcbiAgICB2YXIgcmVxdWVzdCA9IG5ldyBYTUxIdHRwUmVxdWVzdCgpO1xuXG4gICAgcmVxdWVzdC5vcGVuKCdQT1NUJywgdGhpcy5ob3N0LCBmYWxzZSk7XG4gICAgXG4gICAgdHJ5IHtcbiAgICAgICAgcmVxdWVzdC5zZW5kKEpTT04uc3RyaW5naWZ5KHBheWxvYWQpKTtcbiAgICB9IGNhdGNoKGVycm9yKSB7XG4gICAgICAgIHRocm93IGVycm9ycy5JbnZhbGlkQ29ubmVjdGlvbih0aGlzLmhvc3QpO1xuICAgIH1cblxuXG4gICAgLy8gY2hlY2sgcmVxdWVzdC5zdGF0dXNcbiAgICAvLyBUT0RPOiB0aHJvdyBhbiBlcnJvciBoZXJlISBpdCBjYW5ub3Qgc2lsZW50bHkgZmFpbCEhIVxuICAgIC8vaWYgKHJlcXVlc3Quc3RhdHVzICE9PSAyMDApIHtcbiAgICAgICAgLy9yZXR1cm47XG4gICAgLy99XG5cbiAgICB2YXIgcmVzdWx0ID0gcmVxdWVzdC5yZXNwb25zZVRleHQ7XG5cbiAgICB0cnkge1xuICAgICAgICByZXN1bHQgPSBKU09OLnBhcnNlKHJlc3VsdCk7XG4gICAgfSBjYXRjaChlKSB7XG4gICAgICAgIHRocm93IGVycm9ycy5JbnZhbGlkUmVzcG9uc2UocmVzdWx0KTsgICAgICAgICAgICAgICAgXG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbn07XG5cbkh0dHBQcm92aWRlci5wcm90b3R5cGUuc2VuZEFzeW5jID0gZnVuY3Rpb24gKHBheWxvYWQsIGNhbGxiYWNrKSB7XG4gICAgdmFyIHJlcXVlc3QgPSBuZXcgWE1MSHR0cFJlcXVlc3QoKTtcbiAgICByZXF1ZXN0Lm9ucmVhZHlzdGF0ZWNoYW5nZSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBpZiAocmVxdWVzdC5yZWFkeVN0YXRlID09PSA0KSB7XG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gcmVxdWVzdC5yZXNwb25zZVRleHQ7XG4gICAgICAgICAgICB2YXIgZXJyb3IgPSBudWxsO1xuXG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIHJlc3VsdCA9IEpTT04ucGFyc2UocmVzdWx0KTtcbiAgICAgICAgICAgIH0gY2F0Y2goZSkge1xuICAgICAgICAgICAgICAgIGVycm9yID0gZXJyb3JzLkludmFsaWRSZXNwb25zZShyZXN1bHQpOyAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY2FsbGJhY2soZXJyb3IsIHJlc3VsdCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcmVxdWVzdC5vcGVuKCdQT1NUJywgdGhpcy5ob3N0LCB0cnVlKTtcblxuICAgIHRyeSB7XG4gICAgICAgIHJlcXVlc3Quc2VuZChKU09OLnN0cmluZ2lmeShwYXlsb2FkKSk7XG4gICAgfSBjYXRjaChlcnJvcikge1xuICAgICAgICBjYWxsYmFjayhlcnJvcnMuSW52YWxpZENvbm5lY3Rpb24odGhpcy5ob3N0KSk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBIdHRwUHJvdmlkZXI7XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqIFxuICogQGZpbGUgaWNhcC5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy91dGlscycpO1xuXG4vKipcbiAqIFRoaXMgcHJvdG90eXBlIHNob3VsZCBiZSB1c2VkIHRvIGV4dHJhY3QgbmVjZXNzYXJ5IGluZm9ybWF0aW9uIGZyb20gaWJhbiBhZGRyZXNzXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IGliYW5cbiAqL1xudmFyIElDQVAgPSBmdW5jdGlvbiAoaWJhbikge1xuICAgIHRoaXMuX2liYW4gPSBpYmFuO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGNoZWNrIGlmIGljYXAgaXMgY29ycmVjdFxuICpcbiAqIEBtZXRob2QgaXNWYWxpZFxuICogQHJldHVybnMge0Jvb2xlYW59IHRydWUgaWYgaXQgaXMsIG90aGVyd2lzZSBmYWxzZVxuICovXG5JQ0FQLnByb3RvdHlwZS5pc1ZhbGlkID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB1dGlscy5pc0lCQU4odGhpcy5faWJhbik7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gY2hlY2sgaWYgaWJhbiBudW1iZXIgaXMgZGlyZWN0XG4gKlxuICogQG1ldGhvZCBpc0RpcmVjdFxuICogQHJldHVybnMge0Jvb2xlYW59IHRydWUgaWYgaXQgaXMsIG90aGVyd2lzZSBmYWxzZVxuICovXG5JQ0FQLnByb3RvdHlwZS5pc0RpcmVjdCA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5faWJhbi5sZW5ndGggPT09IDM0O1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGNoZWNrIGlmIGliYW4gbnVtYmVyIGlmIGluZGlyZWN0XG4gKlxuICogQG1ldGhvZCBpc0luZGlyZWN0XG4gKiBAcmV0dXJucyB7Qm9vbGVhbn0gdHJ1ZSBpZiBpdCBpcywgb3RoZXJ3aXNlIGZhbHNlXG4gKi9cbklDQVAucHJvdG90eXBlLmlzSW5kaXJlY3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2liYW4ubGVuZ3RoID09PSAyMDtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBnZXQgaWJhbiBjaGVja3N1bVxuICogVXNlcyB0aGUgbW9kLTk3LTEwIGNoZWNrc3VtbWluZyBwcm90b2NvbCAoSVNPL0lFQyA3MDY0OjIwMDMpXG4gKlxuICogQG1ldGhvZCBjaGVja3N1bVxuICogQHJldHVybnMge1N0cmluZ30gY2hlY2tzdW1cbiAqL1xuSUNBUC5wcm90b3R5cGUuY2hlY2tzdW0gPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2liYW4uc3Vic3RyKDIsIDIpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGdldCBpbnN0aXR1dGlvbiBpZGVudGlmaWVyXG4gKiBlZy4gWFJFR1xuICpcbiAqIEBtZXRob2QgaW5zdGl0dXRpb25cbiAqIEByZXR1cm5zIHtTdHJpbmd9IGluc3RpdHV0aW9uIGlkZW50aWZpZXJcbiAqL1xuSUNBUC5wcm90b3R5cGUuaW5zdGl0dXRpb24gPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuaXNJbmRpcmVjdCgpID8gdGhpcy5faWJhbi5zdWJzdHIoNywgNCkgOiAnJztcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBnZXQgY2xpZW50IGlkZW50aWZpZXIgd2l0aGluIGluc3RpdHV0aW9uXG4gKiBlZy4gR0FWT0ZZT1JLXG4gKlxuICogQG1ldGhvZCBjbGllbnRcbiAqIEByZXR1cm5zIHtTdHJpbmd9IGNsaWVudCBpZGVudGlmaWVyXG4gKi9cbklDQVAucHJvdG90eXBlLmNsaWVudCA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5pc0luZGlyZWN0KCkgPyB0aGlzLl9pYmFuLnN1YnN0cigxMSkgOiAnJztcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBnZXQgY2xpZW50IGRpcmVjdCBhZGRyZXNzXG4gKlxuICogQG1ldGhvZCBhZGRyZXNzXG4gKiBAcmV0dXJucyB7U3RyaW5nfSBjbGllbnQgZGlyZWN0IGFkZHJlc3NcbiAqL1xuSUNBUC5wcm90b3R5cGUuYWRkcmVzcyA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5pc0RpcmVjdCgpID8gdGhpcy5faWJhbi5zdWJzdHIoNCkgOiAnJztcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gSUNBUDtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKiogQGZpbGUganNvbnJwYy5qc1xuICogQGF1dGhvcnM6XG4gKiAgIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbnZhciBKc29ucnBjID0gZnVuY3Rpb24gKCkge1xuICAgIC8vIHNpbmdsZXRvbiBwYXR0ZXJuXG4gICAgaWYgKGFyZ3VtZW50cy5jYWxsZWUuX3NpbmdsZXRvbkluc3RhbmNlKSB7XG4gICAgICAgIHJldHVybiBhcmd1bWVudHMuY2FsbGVlLl9zaW5nbGV0b25JbnN0YW5jZTtcbiAgICB9XG4gICAgYXJndW1lbnRzLmNhbGxlZS5fc2luZ2xldG9uSW5zdGFuY2UgPSB0aGlzO1xuXG4gICAgdGhpcy5tZXNzYWdlSWQgPSAxO1xufTtcblxuLyoqXG4gKiBAcmV0dXJuIHtKc29ucnBjfSBzaW5nbGV0b25cbiAqL1xuSnNvbnJwYy5nZXRJbnN0YW5jZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgaW5zdGFuY2UgPSBuZXcgSnNvbnJwYygpO1xuICAgIHJldHVybiBpbnN0YW5jZTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byB2YWxpZCBqc29uIGNyZWF0ZSBwYXlsb2FkIG9iamVjdFxuICpcbiAqIEBtZXRob2QgdG9QYXlsb2FkXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBtZXRob2Qgb2YganNvbnJwYyBjYWxsLCByZXF1aXJlZFxuICogQHBhcmFtIHtBcnJheX0gcGFyYW1zLCBhbiBhcnJheSBvZiBtZXRob2QgcGFyYW1zLCBvcHRpb25hbFxuICogQHJldHVybnMge09iamVjdH0gdmFsaWQganNvbnJwYyBwYXlsb2FkIG9iamVjdFxuICovXG5Kc29ucnBjLnByb3RvdHlwZS50b1BheWxvYWQgPSBmdW5jdGlvbiAobWV0aG9kLCBwYXJhbXMpIHtcbiAgICBpZiAoIW1ldGhvZClcbiAgICAgICAgY29uc29sZS5lcnJvcignanNvbnJwYyBtZXRob2Qgc2hvdWxkIGJlIHNwZWNpZmllZCEnKTtcblxuICAgIHJldHVybiB7XG4gICAgICAgIGpzb25ycGM6ICcyLjAnLFxuICAgICAgICBtZXRob2Q6IG1ldGhvZCxcbiAgICAgICAgcGFyYW1zOiBwYXJhbXMgfHwgW10sXG4gICAgICAgIGlkOiB0aGlzLm1lc3NhZ2VJZCsrXG4gICAgfTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBjaGVjayBpZiBqc29ucnBjIHJlc3BvbnNlIGlzIHZhbGlkXG4gKlxuICogQG1ldGhvZCBpc1ZhbGlkUmVzcG9uc2VcbiAqIEBwYXJhbSB7T2JqZWN0fVxuICogQHJldHVybnMge0Jvb2xlYW59IHRydWUgaWYgcmVzcG9uc2UgaXMgdmFsaWQsIG90aGVyd2lzZSBmYWxzZVxuICovXG5Kc29ucnBjLnByb3RvdHlwZS5pc1ZhbGlkUmVzcG9uc2UgPSBmdW5jdGlvbiAocmVzcG9uc2UpIHtcbiAgICByZXR1cm4gISFyZXNwb25zZSAmJlxuICAgICAgICAhcmVzcG9uc2UuZXJyb3IgJiZcbiAgICAgICAgcmVzcG9uc2UuanNvbnJwYyA9PT0gJzIuMCcgJiZcbiAgICAgICAgdHlwZW9mIHJlc3BvbnNlLmlkID09PSAnbnVtYmVyJyAmJlxuICAgICAgICByZXNwb25zZS5yZXN1bHQgIT09IHVuZGVmaW5lZDsgLy8gb25seSB1bmRlZmluZWQgaXMgbm90IHZhbGlkIGpzb24gb2JqZWN0XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gY3JlYXRlIGJhdGNoIHBheWxvYWQgb2JqZWN0XG4gKlxuICogQG1ldGhvZCB0b0JhdGNoUGF5bG9hZFxuICogQHBhcmFtIHtBcnJheX0gbWVzc2FnZXMsIGFuIGFycmF5IG9mIG9iamVjdHMgd2l0aCBtZXRob2QgKHJlcXVpcmVkKSBhbmQgcGFyYW1zIChvcHRpb25hbCkgZmllbGRzXG4gKiBAcmV0dXJucyB7QXJyYXl9IGJhdGNoIHBheWxvYWRcbiAqL1xuSnNvbnJwYy5wcm90b3R5cGUudG9CYXRjaFBheWxvYWQgPSBmdW5jdGlvbiAobWVzc2FnZXMpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgcmV0dXJuIG1lc3NhZ2VzLm1hcChmdW5jdGlvbiAobWVzc2FnZSkge1xuICAgICAgICByZXR1cm4gc2VsZi50b1BheWxvYWQobWVzc2FnZS5tZXRob2QsIG1lc3NhZ2UucGFyYW1zKTtcbiAgICB9KTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gSnNvbnJwYztcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKipcbiAqIEBmaWxlIG1ldGhvZC5qc1xuICogQGF1dGhvciBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgUmVxdWVzdE1hbmFnZXIgPSByZXF1aXJlKCcuL3JlcXVlc3RtYW5hZ2VyJyk7XG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy91dGlscycpO1xudmFyIGVycm9ycyA9IHJlcXVpcmUoJy4vZXJyb3JzJyk7XG5cbnZhciBNZXRob2QgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHRoaXMubmFtZSA9IG9wdGlvbnMubmFtZTtcbiAgICB0aGlzLmNhbGwgPSBvcHRpb25zLmNhbGw7XG4gICAgdGhpcy5wYXJhbXMgPSBvcHRpb25zLnBhcmFtcyB8fCAwO1xuICAgIHRoaXMuaW5wdXRGb3JtYXR0ZXIgPSBvcHRpb25zLmlucHV0Rm9ybWF0dGVyO1xuICAgIHRoaXMub3V0cHV0Rm9ybWF0dGVyID0gb3B0aW9ucy5vdXRwdXRGb3JtYXR0ZXI7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGRldGVybWluZSBuYW1lIG9mIHRoZSBqc29ucnBjIG1ldGhvZCBiYXNlZCBvbiBhcmd1bWVudHNcbiAqXG4gKiBAbWV0aG9kIGdldENhbGxcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3VtZW50c1xuICogQHJldHVybiB7U3RyaW5nfSBuYW1lIG9mIGpzb25ycGMgbWV0aG9kXG4gKi9cbk1ldGhvZC5wcm90b3R5cGUuZ2V0Q2FsbCA9IGZ1bmN0aW9uIChhcmdzKSB7XG4gICAgcmV0dXJuIHV0aWxzLmlzRnVuY3Rpb24odGhpcy5jYWxsKSA/IHRoaXMuY2FsbChhcmdzKSA6IHRoaXMuY2FsbDtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gZXh0cmFjdCBjYWxsYmFjayBmcm9tIGFycmF5IG9mIGFyZ3VtZW50cy4gTW9kaWZpZXMgaW5wdXQgcGFyYW1cbiAqXG4gKiBAbWV0aG9kIGV4dHJhY3RDYWxsYmFja1xuICogQHBhcmFtIHtBcnJheX0gYXJndW1lbnRzXG4gKiBAcmV0dXJuIHtGdW5jdGlvbnxOdWxsfSBjYWxsYmFjaywgaWYgZXhpc3RzXG4gKi9cbk1ldGhvZC5wcm90b3R5cGUuZXh0cmFjdENhbGxiYWNrID0gZnVuY3Rpb24gKGFyZ3MpIHtcbiAgICBpZiAodXRpbHMuaXNGdW5jdGlvbihhcmdzW2FyZ3MubGVuZ3RoIC0gMV0pKSB7XG4gICAgICAgIHJldHVybiBhcmdzLnBvcCgpOyAvLyBtb2RpZnkgdGhlIGFyZ3MgYXJyYXkhXG4gICAgfVxufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGNoZWNrIGlmIHRoZSBudW1iZXIgb2YgYXJndW1lbnRzIGlzIGNvcnJlY3RcbiAqIFxuICogQG1ldGhvZCB2YWxpZGF0ZUFyZ3NcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3VtZW50c1xuICogQHRocm93cyB7RXJyb3J9IGlmIGl0IGlzIG5vdFxuICovXG5NZXRob2QucHJvdG90eXBlLnZhbGlkYXRlQXJncyA9IGZ1bmN0aW9uIChhcmdzKSB7XG4gICAgaWYgKGFyZ3MubGVuZ3RoICE9PSB0aGlzLnBhcmFtcykge1xuICAgICAgICB0aHJvdyBlcnJvcnMuSW52YWxpZE51bWJlck9mUGFyYW1zKCk7XG4gICAgfVxufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgY2FsbGVkIHRvIGZvcm1hdCBpbnB1dCBhcmdzIG9mIG1ldGhvZFxuICogXG4gKiBAbWV0aG9kIGZvcm1hdElucHV0XG4gKiBAcGFyYW0ge0FycmF5fVxuICogQHJldHVybiB7QXJyYXl9XG4gKi9cbk1ldGhvZC5wcm90b3R5cGUuZm9ybWF0SW5wdXQgPSBmdW5jdGlvbiAoYXJncykge1xuICAgIGlmICghdGhpcy5pbnB1dEZvcm1hdHRlcikge1xuICAgICAgICByZXR1cm4gYXJncztcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5pbnB1dEZvcm1hdHRlci5tYXAoZnVuY3Rpb24gKGZvcm1hdHRlciwgaW5kZXgpIHtcbiAgICAgICAgcmV0dXJuIGZvcm1hdHRlciA/IGZvcm1hdHRlcihhcmdzW2luZGV4XSkgOiBhcmdzW2luZGV4XTtcbiAgICB9KTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBmb3JtYXQgb3V0cHV0KHJlc3VsdCkgb2YgbWV0aG9kXG4gKlxuICogQG1ldGhvZCBmb3JtYXRPdXRwdXRcbiAqIEBwYXJhbSB7T2JqZWN0fVxuICogQHJldHVybiB7T2JqZWN0fVxuICovXG5NZXRob2QucHJvdG90eXBlLmZvcm1hdE91dHB1dCA9IGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICByZXR1cm4gdGhpcy5vdXRwdXRGb3JtYXR0ZXIgJiYgcmVzdWx0ICE9PSBudWxsID8gdGhpcy5vdXRwdXRGb3JtYXR0ZXIocmVzdWx0KSA6IHJlc3VsdDtcbn07XG5cbi8qKlxuICogU2hvdWxkIGF0dGFjaCBmdW5jdGlvbiB0byBtZXRob2RcbiAqIFxuICogQG1ldGhvZCBhdHRhY2hUb09iamVjdFxuICogQHBhcmFtIHtPYmplY3R9XG4gKiBAcGFyYW0ge0Z1bmN0aW9ufVxuICovXG5NZXRob2QucHJvdG90eXBlLmF0dGFjaFRvT2JqZWN0ID0gZnVuY3Rpb24gKG9iaikge1xuICAgIHZhciBmdW5jID0gdGhpcy5zZW5kLmJpbmQodGhpcyk7XG4gICAgZnVuYy5yZXF1ZXN0ID0gdGhpcy5yZXF1ZXN0LmJpbmQodGhpcyk7XG4gICAgZnVuYy5jYWxsID0gdGhpcy5jYWxsOyAvLyB0aGF0J3MgdWdseS4gZmlsdGVyLmpzIHVzZXMgaXRcbiAgICB2YXIgbmFtZSA9IHRoaXMubmFtZS5zcGxpdCgnLicpO1xuICAgIGlmIChuYW1lLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgb2JqW25hbWVbMF1dID0gb2JqW25hbWVbMF1dIHx8IHt9O1xuICAgICAgICBvYmpbbmFtZVswXV1bbmFtZVsxXV0gPSBmdW5jO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIG9ialtuYW1lWzBdXSA9IGZ1bmM7IFxuICAgIH1cbn07XG5cbi8qKlxuICogU2hvdWxkIGNyZWF0ZSBwYXlsb2FkIGZyb20gZ2l2ZW4gaW5wdXQgYXJnc1xuICpcbiAqIEBtZXRob2QgdG9QYXlsb2FkXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzXG4gKiBAcmV0dXJuIHtPYmplY3R9XG4gKi9cbk1ldGhvZC5wcm90b3R5cGUudG9QYXlsb2FkID0gZnVuY3Rpb24gKGFyZ3MpIHtcbiAgICB2YXIgY2FsbCA9IHRoaXMuZ2V0Q2FsbChhcmdzKTtcbiAgICB2YXIgY2FsbGJhY2sgPSB0aGlzLmV4dHJhY3RDYWxsYmFjayhhcmdzKTtcbiAgICB2YXIgcGFyYW1zID0gdGhpcy5mb3JtYXRJbnB1dChhcmdzKTtcbiAgICB0aGlzLnZhbGlkYXRlQXJncyhwYXJhbXMpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgbWV0aG9kOiBjYWxsLFxuICAgICAgICBwYXJhbXM6IHBhcmFtcyxcbiAgICAgICAgY2FsbGJhY2s6IGNhbGxiYWNrXG4gICAgfTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBjcmVhdGUgcHVyZSBKU09OUlBDIHJlcXVlc3Qgd2hpY2ggY2FuIGJlIHVzZWQgaW4gYmF0Y2ggcmVxdWVzdFxuICpcbiAqIEBtZXRob2QgcmVxdWVzdFxuICogQHBhcmFtIHsuLi59IHBhcmFtc1xuICogQHJldHVybiB7T2JqZWN0fSBqc29ucnBjIHJlcXVlc3RcbiAqL1xuTWV0aG9kLnByb3RvdHlwZS5yZXF1ZXN0ID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBwYXlsb2FkID0gdGhpcy50b1BheWxvYWQoQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKSk7XG4gICAgcGF5bG9hZC5mb3JtYXQgPSB0aGlzLmZvcm1hdE91dHB1dC5iaW5kKHRoaXMpO1xuICAgIHJldHVybiBwYXlsb2FkO1xufTtcblxuLyoqXG4gKiBTaG91bGQgc2VuZCByZXF1ZXN0IHRvIHRoZSBBUElcbiAqXG4gKiBAbWV0aG9kIHNlbmRcbiAqIEBwYXJhbSBsaXN0IG9mIHBhcmFtc1xuICogQHJldHVybiByZXN1bHRcbiAqL1xuTWV0aG9kLnByb3RvdHlwZS5zZW5kID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBwYXlsb2FkID0gdGhpcy50b1BheWxvYWQoQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKSk7XG4gICAgaWYgKHBheWxvYWQuY2FsbGJhY2spIHtcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICByZXR1cm4gUmVxdWVzdE1hbmFnZXIuZ2V0SW5zdGFuY2UoKS5zZW5kQXN5bmMocGF5bG9hZCwgZnVuY3Rpb24gKGVyciwgcmVzdWx0KSB7XG4gICAgICAgICAgICBwYXlsb2FkLmNhbGxiYWNrKGVyciwgc2VsZi5mb3JtYXRPdXRwdXQocmVzdWx0KSk7XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5mb3JtYXRPdXRwdXQoUmVxdWVzdE1hbmFnZXIuZ2V0SW5zdGFuY2UoKS5zZW5kKHBheWxvYWQpKTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gTWV0aG9kO1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBcbiAqIEBmaWxlIG5hbWVyZWcuanNcbiAqIEBhdXRob3IgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE1XG4gKi9cblxudmFyIGNvbnRyYWN0ID0gcmVxdWlyZSgnLi9jb250cmFjdCcpO1xuXG52YXIgYWRkcmVzcyA9ICcweGM2ZDlkMmNkNDQ5YTc1NGM0OTQyNjRlMTgwOWM1MGUzNGQ2NDU2MmInO1xuXG52YXIgYWJpID0gW1xuICAgIHtcImNvbnN0YW50XCI6dHJ1ZSxcImlucHV0c1wiOlt7XCJuYW1lXCI6XCJfb3duZXJcIixcInR5cGVcIjpcImFkZHJlc3NcIn1dLFwibmFtZVwiOlwibmFtZVwiLFwib3V0cHV0c1wiOlt7XCJuYW1lXCI6XCJvX25hbWVcIixcInR5cGVcIjpcImJ5dGVzMzJcIn1dLFwidHlwZVwiOlwiZnVuY3Rpb25cIn0sXG4gICAge1wiY29uc3RhbnRcIjp0cnVlLFwiaW5wdXRzXCI6W3tcIm5hbWVcIjpcIl9uYW1lXCIsXCJ0eXBlXCI6XCJieXRlczMyXCJ9XSxcIm5hbWVcIjpcIm93bmVyXCIsXCJvdXRwdXRzXCI6W3tcIm5hbWVcIjpcIlwiLFwidHlwZVwiOlwiYWRkcmVzc1wifV0sXCJ0eXBlXCI6XCJmdW5jdGlvblwifSxcbiAgICB7XCJjb25zdGFudFwiOnRydWUsXCJpbnB1dHNcIjpbe1wibmFtZVwiOlwiX25hbWVcIixcInR5cGVcIjpcImJ5dGVzMzJcIn1dLFwibmFtZVwiOlwiY29udGVudFwiLFwib3V0cHV0c1wiOlt7XCJuYW1lXCI6XCJcIixcInR5cGVcIjpcImJ5dGVzMzJcIn1dLFwidHlwZVwiOlwiZnVuY3Rpb25cIn0sXG4gICAge1wiY29uc3RhbnRcIjp0cnVlLFwiaW5wdXRzXCI6W3tcIm5hbWVcIjpcIl9uYW1lXCIsXCJ0eXBlXCI6XCJieXRlczMyXCJ9XSxcIm5hbWVcIjpcImFkZHJcIixcIm91dHB1dHNcIjpbe1wibmFtZVwiOlwiXCIsXCJ0eXBlXCI6XCJhZGRyZXNzXCJ9XSxcInR5cGVcIjpcImZ1bmN0aW9uXCJ9LFxuICAgIHtcImNvbnN0YW50XCI6ZmFsc2UsXCJpbnB1dHNcIjpbe1wibmFtZVwiOlwiX25hbWVcIixcInR5cGVcIjpcImJ5dGVzMzJcIn1dLFwibmFtZVwiOlwicmVzZXJ2ZVwiLFwib3V0cHV0c1wiOltdLFwidHlwZVwiOlwiZnVuY3Rpb25cIn0sXG4gICAge1wiY29uc3RhbnRcIjp0cnVlLFwiaW5wdXRzXCI6W3tcIm5hbWVcIjpcIl9uYW1lXCIsXCJ0eXBlXCI6XCJieXRlczMyXCJ9XSxcIm5hbWVcIjpcInN1YlJlZ2lzdHJhclwiLFwib3V0cHV0c1wiOlt7XCJuYW1lXCI6XCJvX3N1YlJlZ2lzdHJhclwiLFwidHlwZVwiOlwiYWRkcmVzc1wifV0sXCJ0eXBlXCI6XCJmdW5jdGlvblwifSxcbiAgICB7XCJjb25zdGFudFwiOmZhbHNlLFwiaW5wdXRzXCI6W3tcIm5hbWVcIjpcIl9uYW1lXCIsXCJ0eXBlXCI6XCJieXRlczMyXCJ9LHtcIm5hbWVcIjpcIl9uZXdPd25lclwiLFwidHlwZVwiOlwiYWRkcmVzc1wifV0sXCJuYW1lXCI6XCJ0cmFuc2ZlclwiLFwib3V0cHV0c1wiOltdLFwidHlwZVwiOlwiZnVuY3Rpb25cIn0sXG4gICAge1wiY29uc3RhbnRcIjpmYWxzZSxcImlucHV0c1wiOlt7XCJuYW1lXCI6XCJfbmFtZVwiLFwidHlwZVwiOlwiYnl0ZXMzMlwifSx7XCJuYW1lXCI6XCJfcmVnaXN0cmFyXCIsXCJ0eXBlXCI6XCJhZGRyZXNzXCJ9XSxcIm5hbWVcIjpcInNldFN1YlJlZ2lzdHJhclwiLFwib3V0cHV0c1wiOltdLFwidHlwZVwiOlwiZnVuY3Rpb25cIn0sXG4gICAge1wiY29uc3RhbnRcIjpmYWxzZSxcImlucHV0c1wiOltdLFwibmFtZVwiOlwiUmVnaXN0cmFyXCIsXCJvdXRwdXRzXCI6W10sXCJ0eXBlXCI6XCJmdW5jdGlvblwifSxcbiAgICB7XCJjb25zdGFudFwiOmZhbHNlLFwiaW5wdXRzXCI6W3tcIm5hbWVcIjpcIl9uYW1lXCIsXCJ0eXBlXCI6XCJieXRlczMyXCJ9LHtcIm5hbWVcIjpcIl9hXCIsXCJ0eXBlXCI6XCJhZGRyZXNzXCJ9LHtcIm5hbWVcIjpcIl9wcmltYXJ5XCIsXCJ0eXBlXCI6XCJib29sXCJ9XSxcIm5hbWVcIjpcInNldEFkZHJlc3NcIixcIm91dHB1dHNcIjpbXSxcInR5cGVcIjpcImZ1bmN0aW9uXCJ9LFxuICAgIHtcImNvbnN0YW50XCI6ZmFsc2UsXCJpbnB1dHNcIjpbe1wibmFtZVwiOlwiX25hbWVcIixcInR5cGVcIjpcImJ5dGVzMzJcIn0se1wibmFtZVwiOlwiX2NvbnRlbnRcIixcInR5cGVcIjpcImJ5dGVzMzJcIn1dLFwibmFtZVwiOlwic2V0Q29udGVudFwiLFwib3V0cHV0c1wiOltdLFwidHlwZVwiOlwiZnVuY3Rpb25cIn0sXG4gICAge1wiY29uc3RhbnRcIjpmYWxzZSxcImlucHV0c1wiOlt7XCJuYW1lXCI6XCJfbmFtZVwiLFwidHlwZVwiOlwiYnl0ZXMzMlwifV0sXCJuYW1lXCI6XCJkaXNvd25cIixcIm91dHB1dHNcIjpbXSxcInR5cGVcIjpcImZ1bmN0aW9uXCJ9LFxuICAgIHtcImNvbnN0YW50XCI6dHJ1ZSxcImlucHV0c1wiOlt7XCJuYW1lXCI6XCJfbmFtZVwiLFwidHlwZVwiOlwiYnl0ZXMzMlwifV0sXCJuYW1lXCI6XCJyZWdpc3RlclwiLFwib3V0cHV0c1wiOlt7XCJuYW1lXCI6XCJcIixcInR5cGVcIjpcImFkZHJlc3NcIn1dLFwidHlwZVwiOlwiZnVuY3Rpb25cIn0sXG4gICAge1wiYW5vbnltb3VzXCI6ZmFsc2UsXCJpbnB1dHNcIjpbe1wiaW5kZXhlZFwiOnRydWUsXCJuYW1lXCI6XCJuYW1lXCIsXCJ0eXBlXCI6XCJieXRlczMyXCJ9XSxcIm5hbWVcIjpcIkNoYW5nZWRcIixcInR5cGVcIjpcImV2ZW50XCJ9LFxuICAgIHtcImFub255bW91c1wiOmZhbHNlLFwiaW5wdXRzXCI6W3tcImluZGV4ZWRcIjp0cnVlLFwibmFtZVwiOlwibmFtZVwiLFwidHlwZVwiOlwiYnl0ZXMzMlwifSx7XCJpbmRleGVkXCI6dHJ1ZSxcIm5hbWVcIjpcImFkZHJcIixcInR5cGVcIjpcImFkZHJlc3NcIn1dLFwibmFtZVwiOlwiUHJpbWFyeUNoYW5nZWRcIixcInR5cGVcIjpcImV2ZW50XCJ9XG5dO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNvbnRyYWN0KGFiaSkuYXQoYWRkcmVzcyk7XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqIEBmaWxlIGV0aC5qc1xuICogQGF1dGhvcnM6XG4gKiAgIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbnZhciB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzL3V0aWxzJyk7XG52YXIgUHJvcGVydHkgPSByZXF1aXJlKCcuL3Byb3BlcnR5Jyk7XG5cbi8vLyBAcmV0dXJucyBhbiBhcnJheSBvZiBvYmplY3RzIGRlc2NyaWJpbmcgd2ViMy5ldGggYXBpIG1ldGhvZHNcbnZhciBtZXRob2RzID0gW1xuXTtcblxuLy8vIEByZXR1cm5zIGFuIGFycmF5IG9mIG9iamVjdHMgZGVzY3JpYmluZyB3ZWIzLmV0aCBhcGkgcHJvcGVydGllc1xudmFyIHByb3BlcnRpZXMgPSBbXG4gICAgbmV3IFByb3BlcnR5KHtcbiAgICAgICAgbmFtZTogJ2xpc3RlbmluZycsXG4gICAgICAgIGdldHRlcjogJ25ldF9saXN0ZW5pbmcnXG4gICAgfSksXG4gICAgbmV3IFByb3BlcnR5KHtcbiAgICAgICAgbmFtZTogJ3BlZXJDb3VudCcsXG4gICAgICAgIGdldHRlcjogJ25ldF9wZWVyQ291bnQnLFxuICAgICAgICBvdXRwdXRGb3JtYXR0ZXI6IHV0aWxzLnRvRGVjaW1hbFxuICAgIH0pXG5dO1xuXG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIG1ldGhvZHM6IG1ldGhvZHMsXG4gICAgcHJvcGVydGllczogcHJvcGVydGllc1xufTtcblxuIiwiLypcbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBldGhlcmV1bS5qcy5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGZyZWUgc29mdHdhcmU6IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vciBtb2RpZnlcbiAgICBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbiAgICB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvclxuICAgIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG5cbiAgICBldGhlcmV1bS5qcyBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICAgIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gICAgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZVxuICAgIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gICAgYWxvbmcgd2l0aCBldGhlcmV1bS5qcy4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiovXG4vKipcbiAqIEBmaWxlIHByb3BlcnR5LmpzXG4gKiBAYXV0aG9yIEZhYmlhbiBWb2dlbHN0ZWxsZXIgPGZhYmlhbkBmcm96ZW1hbi5kZT5cbiAqIEBhdXRob3IgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE1XG4gKi9cblxudmFyIFJlcXVlc3RNYW5hZ2VyID0gcmVxdWlyZSgnLi9yZXF1ZXN0bWFuYWdlcicpO1xuXG52YXIgUHJvcGVydHkgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHRoaXMubmFtZSA9IG9wdGlvbnMubmFtZTtcbiAgICB0aGlzLmdldHRlciA9IG9wdGlvbnMuZ2V0dGVyO1xuICAgIHRoaXMuc2V0dGVyID0gb3B0aW9ucy5zZXR0ZXI7XG4gICAgdGhpcy5vdXRwdXRGb3JtYXR0ZXIgPSBvcHRpb25zLm91dHB1dEZvcm1hdHRlcjtcbiAgICB0aGlzLmlucHV0Rm9ybWF0dGVyID0gb3B0aW9ucy5pbnB1dEZvcm1hdHRlcjtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBmb3JtYXQgaW5wdXQgYXJncyBvZiBtZXRob2RcbiAqIFxuICogQG1ldGhvZCBmb3JtYXRJbnB1dFxuICogQHBhcmFtIHtBcnJheX1cbiAqIEByZXR1cm4ge0FycmF5fVxuICovXG5Qcm9wZXJ0eS5wcm90b3R5cGUuZm9ybWF0SW5wdXQgPSBmdW5jdGlvbiAoYXJnKSB7XG4gICAgcmV0dXJuIHRoaXMuaW5wdXRGb3JtYXR0ZXIgPyB0aGlzLmlucHV0Rm9ybWF0dGVyKGFyZykgOiBhcmc7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gZm9ybWF0IG91dHB1dChyZXN1bHQpIG9mIG1ldGhvZFxuICpcbiAqIEBtZXRob2QgZm9ybWF0T3V0cHV0XG4gKiBAcGFyYW0ge09iamVjdH1cbiAqIEByZXR1cm4ge09iamVjdH1cbiAqL1xuUHJvcGVydHkucHJvdG90eXBlLmZvcm1hdE91dHB1dCA9IGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICByZXR1cm4gdGhpcy5vdXRwdXRGb3JtYXR0ZXIgJiYgcmVzdWx0ICE9PSBudWxsID8gdGhpcy5vdXRwdXRGb3JtYXR0ZXIocmVzdWx0KSA6IHJlc3VsdDtcbn07XG5cbi8qKlxuICogU2hvdWxkIGF0dGFjaCBmdW5jdGlvbiB0byBtZXRob2RcbiAqIFxuICogQG1ldGhvZCBhdHRhY2hUb09iamVjdFxuICogQHBhcmFtIHtPYmplY3R9XG4gKiBAcGFyYW0ge0Z1bmN0aW9ufVxuICovXG5Qcm9wZXJ0eS5wcm90b3R5cGUuYXR0YWNoVG9PYmplY3QgPSBmdW5jdGlvbiAob2JqKSB7XG4gICAgdmFyIHByb3RvID0ge1xuICAgICAgICBnZXQ6IHRoaXMuZ2V0LmJpbmQodGhpcyksXG4gICAgfTtcblxuICAgIHZhciBuYW1lcyA9IHRoaXMubmFtZS5zcGxpdCgnLicpO1xuICAgIHZhciBuYW1lID0gbmFtZXNbMF07XG4gICAgaWYgKG5hbWVzLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgb2JqW25hbWVzWzBdXSA9IG9ialtuYW1lc1swXV0gfHwge307XG4gICAgICAgIG9iaiA9IG9ialtuYW1lc1swXV07XG4gICAgICAgIG5hbWUgPSBuYW1lc1sxXTtcbiAgICB9XG4gICAgXG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG9iaiwgbmFtZSwgcHJvdG8pO1xuXG4gICAgdmFyIHRvQXN5bmNOYW1lID0gZnVuY3Rpb24gKHByZWZpeCwgbmFtZSkge1xuICAgICAgICByZXR1cm4gcHJlZml4ICsgbmFtZS5jaGFyQXQoMCkudG9VcHBlckNhc2UoKSArIG5hbWUuc2xpY2UoMSk7XG4gICAgfTtcblxuICAgIG9ialt0b0FzeW5jTmFtZSgnZ2V0JywgbmFtZSldID0gdGhpcy5nZXRBc3luYy5iaW5kKHRoaXMpO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBnZXQgdmFsdWUgb2YgdGhlIHByb3BlcnR5XG4gKlxuICogQG1ldGhvZCBnZXRcbiAqIEByZXR1cm4ge09iamVjdH0gdmFsdWUgb2YgdGhlIHByb3BlcnR5XG4gKi9cblByb3BlcnR5LnByb3RvdHlwZS5nZXQgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuZm9ybWF0T3V0cHV0KFJlcXVlc3RNYW5hZ2VyLmdldEluc3RhbmNlKCkuc2VuZCh7XG4gICAgICAgIG1ldGhvZDogdGhpcy5nZXR0ZXJcbiAgICB9KSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIGFzeW5jaHJvdW5vdXNseSBnZXQgdmFsdWUgb2YgcHJvcGVydHlcbiAqXG4gKiBAbWV0aG9kIGdldEFzeW5jXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufVxuICovXG5Qcm9wZXJ0eS5wcm90b3R5cGUuZ2V0QXN5bmMgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgUmVxdWVzdE1hbmFnZXIuZ2V0SW5zdGFuY2UoKS5zZW5kQXN5bmMoe1xuICAgICAgICBtZXRob2Q6IHRoaXMuZ2V0dGVyXG4gICAgfSwgZnVuY3Rpb24gKGVyciwgcmVzdWx0KSB7XG4gICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhlcnIpO1xuICAgICAgICB9XG4gICAgICAgIGNhbGxiYWNrKGVyciwgc2VsZi5mb3JtYXRPdXRwdXQocmVzdWx0KSk7XG4gICAgfSk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFByb3BlcnR5O1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBAZmlsZSBxdHN5bmMuanNcbiAqIEBhdXRob3JzOlxuICogICBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqICAgTWFyaWFuIE9hbmNlYSA8bWFyaWFuQGV0aGRldi5jb20+XG4gKiBAZGF0ZSAyMDE0XG4gKi9cblxudmFyIFF0U3luY1Byb3ZpZGVyID0gZnVuY3Rpb24gKCkge1xufTtcblxuUXRTeW5jUHJvdmlkZXIucHJvdG90eXBlLnNlbmQgPSBmdW5jdGlvbiAocGF5bG9hZCkge1xuICAgIHZhciByZXN1bHQgPSBuYXZpZ2F0b3IucXQuY2FsbE1ldGhvZChKU09OLnN0cmluZ2lmeShwYXlsb2FkKSk7XG4gICAgcmV0dXJuIEpTT04ucGFyc2UocmVzdWx0KTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUXRTeW5jUHJvdmlkZXI7XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqIFxuICogQGZpbGUgcmVxdWVzdG1hbmFnZXIuanNcbiAqIEBhdXRob3IgSmVmZnJleSBXaWxja2UgPGplZmZAZXRoZGV2LmNvbT5cbiAqIEBhdXRob3IgTWFyZWsgS290ZXdpY3ogPG1hcmVrQGV0aGRldi5jb20+XG4gKiBAYXV0aG9yIE1hcmlhbiBPYW5jZWEgPG1hcmlhbkBldGhkZXYuY29tPlxuICogQGF1dGhvciBGYWJpYW4gVm9nZWxzdGVsbGVyIDxmYWJpYW5AZXRoZGV2LmNvbT5cbiAqIEBhdXRob3IgR2F2IFdvb2QgPGdAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTRcbiAqL1xuXG52YXIgSnNvbnJwYyA9IHJlcXVpcmUoJy4vanNvbnJwYycpO1xudmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMvdXRpbHMnKTtcbnZhciBjID0gcmVxdWlyZSgnLi4vdXRpbHMvY29uZmlnJyk7XG52YXIgZXJyb3JzID0gcmVxdWlyZSgnLi9lcnJvcnMnKTtcblxuLyoqXG4gKiBJdCdzIHJlc3BvbnNpYmxlIGZvciBwYXNzaW5nIG1lc3NhZ2VzIHRvIHByb3ZpZGVyc1xuICogSXQncyBhbHNvIHJlc3BvbnNpYmxlIGZvciBwb2xsaW5nIHRoZSBldGhlcmV1bSBub2RlIGZvciBpbmNvbWluZyBtZXNzYWdlc1xuICogRGVmYXVsdCBwb2xsIHRpbWVvdXQgaXMgMSBzZWNvbmRcbiAqIFNpbmdsZXRvblxuICovXG52YXIgUmVxdWVzdE1hbmFnZXIgPSBmdW5jdGlvbiAocHJvdmlkZXIpIHtcbiAgICAvLyBzaW5nbGV0b24gcGF0dGVyblxuICAgIGlmIChhcmd1bWVudHMuY2FsbGVlLl9zaW5nbGV0b25JbnN0YW5jZSkge1xuICAgICAgICByZXR1cm4gYXJndW1lbnRzLmNhbGxlZS5fc2luZ2xldG9uSW5zdGFuY2U7XG4gICAgfVxuICAgIGFyZ3VtZW50cy5jYWxsZWUuX3NpbmdsZXRvbkluc3RhbmNlID0gdGhpcztcblxuICAgIHRoaXMucHJvdmlkZXIgPSBwcm92aWRlcjtcbiAgICB0aGlzLnBvbGxzID0gW107XG4gICAgdGhpcy50aW1lb3V0ID0gbnVsbDtcbiAgICB0aGlzLnBvbGwoKTtcbn07XG5cbi8qKlxuICogQHJldHVybiB7UmVxdWVzdE1hbmFnZXJ9IHNpbmdsZXRvblxuICovXG5SZXF1ZXN0TWFuYWdlci5nZXRJbnN0YW5jZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgaW5zdGFuY2UgPSBuZXcgUmVxdWVzdE1hbmFnZXIoKTtcbiAgICByZXR1cm4gaW5zdGFuY2U7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIHN5bmNocm9ub3VzbHkgc2VuZCByZXF1ZXN0XG4gKlxuICogQG1ldGhvZCBzZW5kXG4gKiBAcGFyYW0ge09iamVjdH0gZGF0YVxuICogQHJldHVybiB7T2JqZWN0fVxuICovXG5SZXF1ZXN0TWFuYWdlci5wcm90b3R5cGUuc2VuZCA9IGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgaWYgKCF0aGlzLnByb3ZpZGVyKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3JzLkludmFsaWRQcm92aWRlcigpKTtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgdmFyIHBheWxvYWQgPSBKc29ucnBjLmdldEluc3RhbmNlKCkudG9QYXlsb2FkKGRhdGEubWV0aG9kLCBkYXRhLnBhcmFtcyk7XG4gICAgdmFyIHJlc3VsdCA9IHRoaXMucHJvdmlkZXIuc2VuZChwYXlsb2FkKTtcblxuICAgIGlmICghSnNvbnJwYy5nZXRJbnN0YW5jZSgpLmlzVmFsaWRSZXNwb25zZShyZXN1bHQpKSB7XG4gICAgICAgIHRocm93IGVycm9ycy5JbnZhbGlkUmVzcG9uc2UocmVzdWx0KTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0LnJlc3VsdDtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gYXN5bmNocm9ub3VzbHkgc2VuZCByZXF1ZXN0XG4gKlxuICogQG1ldGhvZCBzZW5kQXN5bmNcbiAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFja1xuICovXG5SZXF1ZXN0TWFuYWdlci5wcm90b3R5cGUuc2VuZEFzeW5jID0gZnVuY3Rpb24gKGRhdGEsIGNhbGxiYWNrKSB7XG4gICAgaWYgKCF0aGlzLnByb3ZpZGVyKSB7XG4gICAgICAgIHJldHVybiBjYWxsYmFjayhlcnJvcnMuSW52YWxpZFByb3ZpZGVyKCkpO1xuICAgIH1cblxuICAgIHZhciBwYXlsb2FkID0gSnNvbnJwYy5nZXRJbnN0YW5jZSgpLnRvUGF5bG9hZChkYXRhLm1ldGhvZCwgZGF0YS5wYXJhbXMpO1xuICAgIHRoaXMucHJvdmlkZXIuc2VuZEFzeW5jKHBheWxvYWQsIGZ1bmN0aW9uIChlcnIsIHJlc3VsdCkge1xuICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICByZXR1cm4gY2FsbGJhY2soZXJyKTtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgaWYgKCFKc29ucnBjLmdldEluc3RhbmNlKCkuaXNWYWxpZFJlc3BvbnNlKHJlc3VsdCkpIHtcbiAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhlcnJvcnMuSW52YWxpZFJlc3BvbnNlKHJlc3VsdCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgY2FsbGJhY2sobnVsbCwgcmVzdWx0LnJlc3VsdCk7XG4gICAgfSk7XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gYXN5bmNocm9ub3VzbHkgc2VuZCBiYXRjaCByZXF1ZXN0XG4gKlxuICogQG1ldGhvZCBzZW5kQmF0Y2hcbiAqIEBwYXJhbSB7QXJyYXl9IGJhdGNoIGRhdGFcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrXG4gKi9cblJlcXVlc3RNYW5hZ2VyLnByb3RvdHlwZS5zZW5kQmF0Y2ggPSBmdW5jdGlvbiAoZGF0YSwgY2FsbGJhY2spIHtcbiAgICBpZiAoIXRoaXMucHJvdmlkZXIpIHtcbiAgICAgICAgcmV0dXJuIGNhbGxiYWNrKGVycm9ycy5JbnZhbGlkUHJvdmlkZXIoKSk7XG4gICAgfVxuXG4gICAgdmFyIHBheWxvYWQgPSBKc29ucnBjLmdldEluc3RhbmNlKCkudG9CYXRjaFBheWxvYWQoZGF0YSk7XG5cbiAgICB0aGlzLnByb3ZpZGVyLnNlbmRBc3luYyhwYXlsb2FkLCBmdW5jdGlvbiAoZXJyLCByZXN1bHRzKSB7XG4gICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhlcnIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCF1dGlscy5pc0FycmF5KHJlc3VsdHMpKSB7XG4gICAgICAgICAgICByZXR1cm4gY2FsbGJhY2soZXJyb3JzLkludmFsaWRSZXNwb25zZShyZXN1bHRzKSk7XG4gICAgICAgIH1cblxuICAgICAgICBjYWxsYmFjayhlcnIsIHJlc3VsdHMpO1xuICAgIH0pOyBcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gc2V0IHByb3ZpZGVyIG9mIHJlcXVlc3QgbWFuYWdlclxuICpcbiAqIEBtZXRob2Qgc2V0UHJvdmlkZXJcbiAqIEBwYXJhbSB7T2JqZWN0fVxuICovXG5SZXF1ZXN0TWFuYWdlci5wcm90b3R5cGUuc2V0UHJvdmlkZXIgPSBmdW5jdGlvbiAocCkge1xuICAgIHRoaXMucHJvdmlkZXIgPSBwO1xufTtcblxuLypqc2hpbnQgbWF4cGFyYW1zOjQgKi9cblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBzdGFydCBwb2xsaW5nXG4gKlxuICogQG1ldGhvZCBzdGFydFBvbGxpbmdcbiAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhXG4gKiBAcGFyYW0ge051bWJlcn0gcG9sbElkXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFja1xuICogQHBhcmFtIHtGdW5jdGlvbn0gdW5pbnN0YWxsXG4gKlxuICogQHRvZG8gY2xlYW51cCBudW1iZXIgb2YgcGFyYW1zXG4gKi9cblJlcXVlc3RNYW5hZ2VyLnByb3RvdHlwZS5zdGFydFBvbGxpbmcgPSBmdW5jdGlvbiAoZGF0YSwgcG9sbElkLCBjYWxsYmFjaywgdW5pbnN0YWxsKSB7XG4gICAgdGhpcy5wb2xscy5wdXNoKHtkYXRhOiBkYXRhLCBpZDogcG9sbElkLCBjYWxsYmFjazogY2FsbGJhY2ssIHVuaW5zdGFsbDogdW5pbnN0YWxsfSk7XG59O1xuLypqc2hpbnQgbWF4cGFyYW1zOjMgKi9cblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBzdG9wIHBvbGxpbmcgZm9yIGZpbHRlciB3aXRoIGdpdmVuIGlkXG4gKlxuICogQG1ldGhvZCBzdG9wUG9sbGluZ1xuICogQHBhcmFtIHtOdW1iZXJ9IHBvbGxJZFxuICovXG5SZXF1ZXN0TWFuYWdlci5wcm90b3R5cGUuc3RvcFBvbGxpbmcgPSBmdW5jdGlvbiAocG9sbElkKSB7XG4gICAgZm9yICh2YXIgaSA9IHRoaXMucG9sbHMubGVuZ3RoOyBpLS07KSB7XG4gICAgICAgIHZhciBwb2xsID0gdGhpcy5wb2xsc1tpXTtcbiAgICAgICAgaWYgKHBvbGwuaWQgPT09IHBvbGxJZCkge1xuICAgICAgICAgICAgdGhpcy5wb2xscy5zcGxpY2UoaSwgMSk7XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSBjYWxsZWQgdG8gcmVzZXQgcG9sbGluZyBtZWNoYW5pc20gb2YgcmVxdWVzdCBtYW5hZ2VyXG4gKlxuICogQG1ldGhvZCByZXNldFxuICovXG5SZXF1ZXN0TWFuYWdlci5wcm90b3R5cGUucmVzZXQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5wb2xscy5mb3JFYWNoKGZ1bmN0aW9uIChwb2xsKSB7XG4gICAgICAgIHBvbGwudW5pbnN0YWxsKHBvbGwuaWQpOyBcbiAgICB9KTtcbiAgICB0aGlzLnBvbGxzID0gW107XG5cbiAgICBpZiAodGhpcy50aW1lb3V0KSB7XG4gICAgICAgIGNsZWFyVGltZW91dCh0aGlzLnRpbWVvdXQpO1xuICAgICAgICB0aGlzLnRpbWVvdXQgPSBudWxsO1xuICAgIH1cbiAgICB0aGlzLnBvbGwoKTtcbn07XG5cbi8qKlxuICogU2hvdWxkIGJlIGNhbGxlZCB0byBwb2xsIGZvciBjaGFuZ2VzIG9uIGZpbHRlciB3aXRoIGdpdmVuIGlkXG4gKlxuICogQG1ldGhvZCBwb2xsXG4gKi9cblJlcXVlc3RNYW5hZ2VyLnByb3RvdHlwZS5wb2xsID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMudGltZW91dCA9IHNldFRpbWVvdXQodGhpcy5wb2xsLmJpbmQodGhpcyksIGMuRVRIX1BPTExJTkdfVElNRU9VVCk7XG5cbiAgICBpZiAoIXRoaXMucG9sbHMubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoIXRoaXMucHJvdmlkZXIpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihlcnJvcnMuSW52YWxpZFByb3ZpZGVyKCkpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIHBheWxvYWQgPSBKc29ucnBjLmdldEluc3RhbmNlKCkudG9CYXRjaFBheWxvYWQodGhpcy5wb2xscy5tYXAoZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgICAgcmV0dXJuIGRhdGEuZGF0YTtcbiAgICB9KSk7XG5cbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdGhpcy5wcm92aWRlci5zZW5kQXN5bmMocGF5bG9hZCwgZnVuY3Rpb24gKGVycm9yLCByZXN1bHRzKSB7XG4gICAgICAgIC8vIFRPRE86IGNvbnNvbGUgbG9nP1xuICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICAgICAgXG4gICAgICAgIGlmICghdXRpbHMuaXNBcnJheShyZXN1bHRzKSkge1xuICAgICAgICAgICAgdGhyb3cgZXJyb3JzLkludmFsaWRSZXNwb25zZShyZXN1bHRzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJlc3VsdHMubWFwKGZ1bmN0aW9uIChyZXN1bHQsIGluZGV4KSB7XG4gICAgICAgICAgICByZXN1bHQuY2FsbGJhY2sgPSBzZWxmLnBvbGxzW2luZGV4XS5jYWxsYmFjaztcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH0pLmZpbHRlcihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgICB2YXIgdmFsaWQgPSBKc29ucnBjLmdldEluc3RhbmNlKCkuaXNWYWxpZFJlc3BvbnNlKHJlc3VsdCk7XG4gICAgICAgICAgICBpZiAoIXZhbGlkKSB7XG4gICAgICAgICAgICAgICAgcmVzdWx0LmNhbGxiYWNrKGVycm9ycy5JbnZhbGlkUmVzcG9uc2UocmVzdWx0KSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdmFsaWQ7XG4gICAgICAgIH0pLmZpbHRlcihmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgICByZXR1cm4gdXRpbHMuaXNBcnJheShyZXN1bHQucmVzdWx0KSAmJiByZXN1bHQucmVzdWx0Lmxlbmd0aCA+IDA7XG4gICAgICAgIH0pLmZvckVhY2goZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgcmVzdWx0LmNhbGxiYWNrKG51bGwsIHJlc3VsdC5yZXN1bHQpO1xuICAgICAgICB9KTtcbiAgICB9KTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVxdWVzdE1hbmFnZXI7XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqIEBmaWxlIHNoaC5qc1xuICogQGF1dGhvcnM6XG4gKiAgIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbnZhciBNZXRob2QgPSByZXF1aXJlKCcuL21ldGhvZCcpO1xudmFyIGZvcm1hdHRlcnMgPSByZXF1aXJlKCcuL2Zvcm1hdHRlcnMnKTtcblxudmFyIHBvc3QgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAncG9zdCcsIFxuICAgIGNhbGw6ICdzaGhfcG9zdCcsIFxuICAgIHBhcmFtczogMSxcbiAgICBpbnB1dEZvcm1hdHRlcjogW2Zvcm1hdHRlcnMuaW5wdXRQb3N0Rm9ybWF0dGVyXVxufSk7XG5cbnZhciBuZXdJZGVudGl0eSA9IG5ldyBNZXRob2Qoe1xuICAgIG5hbWU6ICduZXdJZGVudGl0eScsXG4gICAgY2FsbDogJ3NoaF9uZXdJZGVudGl0eScsXG4gICAgcGFyYW1zOiAwXG59KTtcblxudmFyIGhhc0lkZW50aXR5ID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2hhc0lkZW50aXR5JyxcbiAgICBjYWxsOiAnc2hoX2hhc0lkZW50aXR5JyxcbiAgICBwYXJhbXM6IDFcbn0pO1xuXG52YXIgbmV3R3JvdXAgPSBuZXcgTWV0aG9kKHtcbiAgICBuYW1lOiAnbmV3R3JvdXAnLFxuICAgIGNhbGw6ICdzaGhfbmV3R3JvdXAnLFxuICAgIHBhcmFtczogMFxufSk7XG5cbnZhciBhZGRUb0dyb3VwID0gbmV3IE1ldGhvZCh7XG4gICAgbmFtZTogJ2FkZFRvR3JvdXAnLFxuICAgIGNhbGw6ICdzaGhfYWRkVG9Hcm91cCcsXG4gICAgcGFyYW1zOiAwXG59KTtcblxudmFyIG1ldGhvZHMgPSBbXG4gICAgcG9zdCxcbiAgICBuZXdJZGVudGl0eSxcbiAgICBoYXNJZGVudGl0eSxcbiAgICBuZXdHcm91cCxcbiAgICBhZGRUb0dyb3VwXG5dO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBtZXRob2RzOiBtZXRob2RzXG59O1xuXG4iLCIvKlxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIGV0aGVyZXVtLmpzLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuICAgIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieVxuICAgIHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4gICAgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cblxuICAgIGV0aGVyZXVtLmpzIGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4gICAgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAgICBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gICAgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIGV0aGVyZXVtLmpzLiAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuZ251Lm9yZy9saWNlbnNlcy8+LlxuKi9cbi8qKiBcbiAqIEBmaWxlIHRyYW5zZmVyLmpzXG4gKiBAYXV0aG9yIE1hcmVrIEtvdGV3aWN6IDxtYXJla0BldGhkZXYuY29tPlxuICogQGRhdGUgMjAxNVxuICovXG5cbnZhciB3ZWIzID0gcmVxdWlyZSgnLi4vd2ViMycpO1xudmFyIElDQVAgPSByZXF1aXJlKCcuL2ljYXAnKTtcbnZhciBuYW1lcmVnID0gcmVxdWlyZSgnLi9uYW1lcmVnJyk7XG52YXIgY29udHJhY3QgPSByZXF1aXJlKCcuL2NvbnRyYWN0Jyk7XG5cbi8qKlxuICogU2hvdWxkIGJlIHVzZWQgdG8gbWFrZSBJQ0FQIHRyYW5zZmVyXG4gKlxuICogQG1ldGhvZCB0cmFuc2ZlclxuICogQHBhcmFtIHtTdHJpbmd9IGliYW4gbnVtYmVyXG4gKiBAcGFyYW0ge1N0cmluZ30gZnJvbSAoYWRkcmVzcylcbiAqIEBwYXJhbSB7VmFsdWV9IHZhbHVlIHRvIGJlIHRyYW5mZXJlZFxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2ssIGNhbGxiYWNrXG4gKi9cbnZhciB0cmFuc2ZlciA9IGZ1bmN0aW9uIChmcm9tLCBpYmFuLCB2YWx1ZSwgY2FsbGJhY2spIHtcbiAgICB2YXIgaWNhcCA9IG5ldyBJQ0FQKGliYW4pOyBcbiAgICBpZiAoIWljYXAuaXNWYWxpZCgpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCBpYmFuIGFkZHJlc3MnKTtcbiAgICB9XG5cbiAgICBpZiAoaWNhcC5pc0RpcmVjdCgpKSB7XG4gICAgICAgIHJldHVybiB0cmFuc2ZlclRvQWRkcmVzcyhmcm9tLCBpY2FwLmFkZHJlc3MoKSwgdmFsdWUsIGNhbGxiYWNrKTtcbiAgICB9XG4gICAgXG4gICAgaWYgKCFjYWxsYmFjaykge1xuICAgICAgICB2YXIgYWRkcmVzcyA9IG5hbWVyZWcuYWRkcihpY2FwLmluc3RpdHV0aW9uKCkpO1xuICAgICAgICByZXR1cm4gZGVwb3NpdChmcm9tLCBhZGRyZXNzLCB2YWx1ZSwgaWNhcC5jbGllbnQoKSk7XG4gICAgfVxuXG4gICAgbmFtZXJlZy5hZGRyKGljYXAuaW5zaXR1dGlvbigpLCBmdW5jdGlvbiAoZXJyLCBhZGRyZXNzKSB7XG4gICAgICAgIHJldHVybiBkZXBvc2l0KGZyb20sIGFkZHJlc3MsIHZhbHVlLCBpY2FwLmNsaWVudCgpLCBjYWxsYmFjayk7XG4gICAgfSk7XG4gICAgXG59O1xuXG4vKipcbiAqIFNob3VsZCBiZSB1c2VkIHRvIHRyYW5zZmVyIGZ1bmRzIHRvIGNlcnRhaW4gYWRkcmVzc1xuICpcbiAqIEBtZXRob2QgdHJhbnNmZXJUb0FkZHJlc3NcbiAqIEBwYXJhbSB7U3RyaW5nfSBhZGRyZXNzXG4gKiBAcGFyYW0ge1N0cmluZ30gZnJvbSAoYWRkcmVzcylcbiAqIEBwYXJhbSB7VmFsdWV9IHZhbHVlIHRvIGJlIHRyYW5mZXJlZFxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2ssIGNhbGxiYWNrXG4gKi9cbnZhciB0cmFuc2ZlclRvQWRkcmVzcyA9IGZ1bmN0aW9uIChmcm9tLCBhZGRyZXNzLCB2YWx1ZSwgY2FsbGJhY2spIHtcbiAgICByZXR1cm4gd2ViMy5ldGguc2VuZFRyYW5zYWN0aW9uKHtcbiAgICAgICAgYWRkcmVzczogYWRkcmVzcyxcbiAgICAgICAgZnJvbTogZnJvbSxcbiAgICAgICAgdmFsdWU6IHZhbHVlXG4gICAgfSwgY2FsbGJhY2spO1xufTtcblxuLyoqXG4gKiBTaG91bGQgYmUgdXNlZCB0byBkZXBvc2l0IGZ1bmRzIHRvIGdlbmVyaWMgRXhjaGFuZ2UgY29udHJhY3QgKG11c3QgaW1wbGVtZW50IGRlcG9zaXQoYnl0ZXMzMikgbWV0aG9kISlcbiAqXG4gKiBAbWV0aG9kIGRlcG9zaXRcbiAqIEBwYXJhbSB7U3RyaW5nfSBhZGRyZXNzXG4gKiBAcGFyYW0ge1N0cmluZ30gZnJvbSAoYWRkcmVzcylcbiAqIEBwYXJhbSB7VmFsdWV9IHZhbHVlIHRvIGJlIHRyYW5mZXJlZFxuICogQHBhcmFtIHtTdHJpbmd9IGNsaWVudCB1bmlxdWUgaWRlbnRpZmllclxuICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2ssIGNhbGxiYWNrXG4gKi9cbnZhciBkZXBvc2l0ID0gZnVuY3Rpb24gKGZyb20sIGFkZHJlc3MsIHZhbHVlLCBjbGllbnQsIGNhbGxiYWNrKSB7XG4gICAgdmFyIGFiaSA9IFt7XCJjb25zdGFudFwiOmZhbHNlLFwiaW5wdXRzXCI6W3tcIm5hbWVcIjpcIm5hbWVcIixcInR5cGVcIjpcImJ5dGVzMzJcIn1dLFwibmFtZVwiOlwiZGVwb3NpdFwiLFwib3V0cHV0c1wiOltdLFwidHlwZVwiOlwiZnVuY3Rpb25cIn1dO1xuICAgIHJldHVybiBjb250cmFjdChhYmkpLmF0KGFkZHJlc3MpLmRlcG9zaXQoY2xpZW50LCB7XG4gICAgICAgIGZyb206IGZyb20sXG4gICAgICAgIHZhbHVlOiB2YWx1ZVxuICAgIH0sIGNhbGxiYWNrKTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gdHJhbnNmZXI7XG5cbiIsIi8qXG4gICAgVGhpcyBmaWxlIGlzIHBhcnQgb2YgZXRoZXJldW0uanMuXG5cbiAgICBldGhlcmV1bS5qcyBpcyBmcmVlIHNvZnR3YXJlOiB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3IgbW9kaWZ5XG4gICAgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5XG4gICAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbiwgZWl0aGVyIHZlcnNpb24gMyBvZiB0aGUgTGljZW5zZSwgb3JcbiAgICAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG4gICAgZXRoZXJldW0uanMgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAgICBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuICAgIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAgICBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggZXRoZXJldW0uanMuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuLyoqIEBmaWxlIHdhdGNoZXMuanNcbiAqIEBhdXRob3JzOlxuICogICBNYXJlayBLb3Rld2ljeiA8bWFyZWtAZXRoZGV2LmNvbT5cbiAqIEBkYXRlIDIwMTVcbiAqL1xuXG52YXIgTWV0aG9kID0gcmVxdWlyZSgnLi9tZXRob2QnKTtcblxuLy8vIEByZXR1cm5zIGFuIGFycmF5IG9mIG9iamVjdHMgZGVzY3JpYmluZyB3ZWIzLmV0aC5maWx0ZXIgYXBpIG1ldGhvZHNcbnZhciBldGggPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIG5ld0ZpbHRlckNhbGwgPSBmdW5jdGlvbiAoYXJncykge1xuICAgICAgICB2YXIgdHlwZSA9IGFyZ3NbMF07XG5cbiAgICAgICAgc3dpdGNoKHR5cGUpIHtcbiAgICAgICAgICAgIGNhc2UgJ2xhdGVzdCc6XG4gICAgICAgICAgICAgICAgYXJncy5wb3AoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnBhcmFtcyA9IDA7XG4gICAgICAgICAgICAgICAgcmV0dXJuICdldGhfbmV3QmxvY2tGaWx0ZXInO1xuICAgICAgICAgICAgY2FzZSAncGVuZGluZyc6XG4gICAgICAgICAgICAgICAgYXJncy5wb3AoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnBhcmFtcyA9IDA7XG4gICAgICAgICAgICAgICAgcmV0dXJuICdldGhfbmV3UGVuZGluZ1RyYW5zYWN0aW9uRmlsdGVyJztcbiAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgcmV0dXJuICdldGhfbmV3RmlsdGVyJztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgbmV3RmlsdGVyID0gbmV3IE1ldGhvZCh7XG4gICAgICAgIG5hbWU6ICduZXdGaWx0ZXInLFxuICAgICAgICBjYWxsOiBuZXdGaWx0ZXJDYWxsLFxuICAgICAgICBwYXJhbXM6IDFcbiAgICB9KTtcblxuICAgIHZhciB1bmluc3RhbGxGaWx0ZXIgPSBuZXcgTWV0aG9kKHtcbiAgICAgICAgbmFtZTogJ3VuaW5zdGFsbEZpbHRlcicsXG4gICAgICAgIGNhbGw6ICdldGhfdW5pbnN0YWxsRmlsdGVyJyxcbiAgICAgICAgcGFyYW1zOiAxXG4gICAgfSk7XG5cbiAgICB2YXIgZ2V0TG9ncyA9IG5ldyBNZXRob2Qoe1xuICAgICAgICBuYW1lOiAnZ2V0TG9ncycsXG4gICAgICAgIGNhbGw6ICdldGhfZ2V0RmlsdGVyTG9ncycsXG4gICAgICAgIHBhcmFtczogMVxuICAgIH0pO1xuXG4gICAgdmFyIHBvbGwgPSBuZXcgTWV0aG9kKHtcbiAgICAgICAgbmFtZTogJ3BvbGwnLFxuICAgICAgICBjYWxsOiAnZXRoX2dldEZpbHRlckNoYW5nZXMnLFxuICAgICAgICBwYXJhbXM6IDFcbiAgICB9KTtcblxuICAgIHJldHVybiBbXG4gICAgICAgIG5ld0ZpbHRlcixcbiAgICAgICAgdW5pbnN0YWxsRmlsdGVyLFxuICAgICAgICBnZXRMb2dzLFxuICAgICAgICBwb2xsXG4gICAgXTtcbn07XG5cbi8vLyBAcmV0dXJucyBhbiBhcnJheSBvZiBvYmplY3RzIGRlc2NyaWJpbmcgd2ViMy5zaGgud2F0Y2ggYXBpIG1ldGhvZHNcbnZhciBzaGggPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIG5ld0ZpbHRlciA9IG5ldyBNZXRob2Qoe1xuICAgICAgICBuYW1lOiAnbmV3RmlsdGVyJyxcbiAgICAgICAgY2FsbDogJ3NoaF9uZXdGaWx0ZXInLFxuICAgICAgICBwYXJhbXM6IDFcbiAgICB9KTtcblxuICAgIHZhciB1bmluc3RhbGxGaWx0ZXIgPSBuZXcgTWV0aG9kKHtcbiAgICAgICAgbmFtZTogJ3VuaW5zdGFsbEZpbHRlcicsXG4gICAgICAgIGNhbGw6ICdzaGhfdW5pbnN0YWxsRmlsdGVyJyxcbiAgICAgICAgcGFyYW1zOiAxXG4gICAgfSk7XG5cbiAgICB2YXIgZ2V0TG9ncyA9IG5ldyBNZXRob2Qoe1xuICAgICAgICBuYW1lOiAnZ2V0TG9ncycsXG4gICAgICAgIGNhbGw6ICdzaGhfZ2V0TWVzc2FnZXMnLFxuICAgICAgICBwYXJhbXM6IDFcbiAgICB9KTtcblxuICAgIHZhciBwb2xsID0gbmV3IE1ldGhvZCh7XG4gICAgICAgIG5hbWU6ICdwb2xsJyxcbiAgICAgICAgY2FsbDogJ3NoaF9nZXRGaWx0ZXJDaGFuZ2VzJyxcbiAgICAgICAgcGFyYW1zOiAxXG4gICAgfSk7XG5cbiAgICByZXR1cm4gW1xuICAgICAgICBuZXdGaWx0ZXIsXG4gICAgICAgIHVuaW5zdGFsbEZpbHRlcixcbiAgICAgICAgZ2V0TG9ncyxcbiAgICAgICAgcG9sbFxuICAgIF07XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBldGg6IGV0aCxcbiAgICBzaGg6IHNoaFxufTtcblxuIixudWxsLCI7KGZ1bmN0aW9uIChyb290LCBmYWN0b3J5KSB7XG5cdGlmICh0eXBlb2YgZXhwb3J0cyA9PT0gXCJvYmplY3RcIikge1xuXHRcdC8vIENvbW1vbkpTXG5cdFx0bW9kdWxlLmV4cG9ydHMgPSBleHBvcnRzID0gZmFjdG9yeSgpO1xuXHR9XG5cdGVsc2UgaWYgKHR5cGVvZiBkZWZpbmUgPT09IFwiZnVuY3Rpb25cIiAmJiBkZWZpbmUuYW1kKSB7XG5cdFx0Ly8gQU1EXG5cdFx0ZGVmaW5lKFtdLCBmYWN0b3J5KTtcblx0fVxuXHRlbHNlIHtcblx0XHQvLyBHbG9iYWwgKGJyb3dzZXIpXG5cdFx0cm9vdC5DcnlwdG9KUyA9IGZhY3RvcnkoKTtcblx0fVxufSh0aGlzLCBmdW5jdGlvbiAoKSB7XG5cblx0LyoqXG5cdCAqIENyeXB0b0pTIGNvcmUgY29tcG9uZW50cy5cblx0ICovXG5cdHZhciBDcnlwdG9KUyA9IENyeXB0b0pTIHx8IChmdW5jdGlvbiAoTWF0aCwgdW5kZWZpbmVkKSB7XG5cdCAgICAvKipcblx0ICAgICAqIENyeXB0b0pTIG5hbWVzcGFjZS5cblx0ICAgICAqL1xuXHQgICAgdmFyIEMgPSB7fTtcblxuXHQgICAgLyoqXG5cdCAgICAgKiBMaWJyYXJ5IG5hbWVzcGFjZS5cblx0ICAgICAqL1xuXHQgICAgdmFyIENfbGliID0gQy5saWIgPSB7fTtcblxuXHQgICAgLyoqXG5cdCAgICAgKiBCYXNlIG9iamVjdCBmb3IgcHJvdG90eXBhbCBpbmhlcml0YW5jZS5cblx0ICAgICAqL1xuXHQgICAgdmFyIEJhc2UgPSBDX2xpYi5CYXNlID0gKGZ1bmN0aW9uICgpIHtcblx0ICAgICAgICBmdW5jdGlvbiBGKCkge31cblxuXHQgICAgICAgIHJldHVybiB7XG5cdCAgICAgICAgICAgIC8qKlxuXHQgICAgICAgICAgICAgKiBDcmVhdGVzIGEgbmV3IG9iamVjdCB0aGF0IGluaGVyaXRzIGZyb20gdGhpcyBvYmplY3QuXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvdmVycmlkZXMgUHJvcGVydGllcyB0byBjb3B5IGludG8gdGhlIG5ldyBvYmplY3QuXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqIEByZXR1cm4ge09iamVjdH0gVGhlIG5ldyBvYmplY3QuXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqIEBzdGF0aWNcblx0ICAgICAgICAgICAgICpcblx0ICAgICAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgICAgICpcblx0ICAgICAgICAgICAgICogICAgIHZhciBNeVR5cGUgPSBDcnlwdG9KUy5saWIuQmFzZS5leHRlbmQoe1xuXHQgICAgICAgICAgICAgKiAgICAgICAgIGZpZWxkOiAndmFsdWUnLFxuXHQgICAgICAgICAgICAgKlxuXHQgICAgICAgICAgICAgKiAgICAgICAgIG1ldGhvZDogZnVuY3Rpb24gKCkge1xuXHQgICAgICAgICAgICAgKiAgICAgICAgIH1cblx0ICAgICAgICAgICAgICogICAgIH0pO1xuXHQgICAgICAgICAgICAgKi9cblx0ICAgICAgICAgICAgZXh0ZW5kOiBmdW5jdGlvbiAob3ZlcnJpZGVzKSB7XG5cdCAgICAgICAgICAgICAgICAvLyBTcGF3blxuXHQgICAgICAgICAgICAgICAgRi5wcm90b3R5cGUgPSB0aGlzO1xuXHQgICAgICAgICAgICAgICAgdmFyIHN1YnR5cGUgPSBuZXcgRigpO1xuXG5cdCAgICAgICAgICAgICAgICAvLyBBdWdtZW50XG5cdCAgICAgICAgICAgICAgICBpZiAob3ZlcnJpZGVzKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgc3VidHlwZS5taXhJbihvdmVycmlkZXMpO1xuXHQgICAgICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgICAgICAvLyBDcmVhdGUgZGVmYXVsdCBpbml0aWFsaXplclxuXHQgICAgICAgICAgICAgICAgaWYgKCFzdWJ0eXBlLmhhc093blByb3BlcnR5KCdpbml0JykpIHtcblx0ICAgICAgICAgICAgICAgICAgICBzdWJ0eXBlLmluaXQgPSBmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIHN1YnR5cGUuJHN1cGVyLmluaXQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcblx0ICAgICAgICAgICAgICAgICAgICB9O1xuXHQgICAgICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgICAgICAvLyBJbml0aWFsaXplcidzIHByb3RvdHlwZSBpcyB0aGUgc3VidHlwZSBvYmplY3Rcblx0ICAgICAgICAgICAgICAgIHN1YnR5cGUuaW5pdC5wcm90b3R5cGUgPSBzdWJ0eXBlO1xuXG5cdCAgICAgICAgICAgICAgICAvLyBSZWZlcmVuY2Ugc3VwZXJ0eXBlXG5cdCAgICAgICAgICAgICAgICBzdWJ0eXBlLiRzdXBlciA9IHRoaXM7XG5cblx0ICAgICAgICAgICAgICAgIHJldHVybiBzdWJ0eXBlO1xuXHQgICAgICAgICAgICB9LFxuXG5cdCAgICAgICAgICAgIC8qKlxuXHQgICAgICAgICAgICAgKiBFeHRlbmRzIHRoaXMgb2JqZWN0IGFuZCBydW5zIHRoZSBpbml0IG1ldGhvZC5cblx0ICAgICAgICAgICAgICogQXJndW1lbnRzIHRvIGNyZWF0ZSgpIHdpbGwgYmUgcGFzc2VkIHRvIGluaXQoKS5cblx0ICAgICAgICAgICAgICpcblx0ICAgICAgICAgICAgICogQHJldHVybiB7T2JqZWN0fSBUaGUgbmV3IG9iamVjdC5cblx0ICAgICAgICAgICAgICpcblx0ICAgICAgICAgICAgICogQHN0YXRpY1xuXHQgICAgICAgICAgICAgKlxuXHQgICAgICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAgICAgKlxuXHQgICAgICAgICAgICAgKiAgICAgdmFyIGluc3RhbmNlID0gTXlUeXBlLmNyZWF0ZSgpO1xuXHQgICAgICAgICAgICAgKi9cblx0ICAgICAgICAgICAgY3JlYXRlOiBmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgICAgICAgICB2YXIgaW5zdGFuY2UgPSB0aGlzLmV4dGVuZCgpO1xuXHQgICAgICAgICAgICAgICAgaW5zdGFuY2UuaW5pdC5hcHBseShpbnN0YW5jZSwgYXJndW1lbnRzKTtcblxuXHQgICAgICAgICAgICAgICAgcmV0dXJuIGluc3RhbmNlO1xuXHQgICAgICAgICAgICB9LFxuXG5cdCAgICAgICAgICAgIC8qKlxuXHQgICAgICAgICAgICAgKiBJbml0aWFsaXplcyBhIG5ld2x5IGNyZWF0ZWQgb2JqZWN0LlxuXHQgICAgICAgICAgICAgKiBPdmVycmlkZSB0aGlzIG1ldGhvZCB0byBhZGQgc29tZSBsb2dpYyB3aGVuIHlvdXIgb2JqZWN0cyBhcmUgY3JlYXRlZC5cblx0ICAgICAgICAgICAgICpcblx0ICAgICAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgICAgICpcblx0ICAgICAgICAgICAgICogICAgIHZhciBNeVR5cGUgPSBDcnlwdG9KUy5saWIuQmFzZS5leHRlbmQoe1xuXHQgICAgICAgICAgICAgKiAgICAgICAgIGluaXQ6IGZ1bmN0aW9uICgpIHtcblx0ICAgICAgICAgICAgICogICAgICAgICAgICAgLy8gLi4uXG5cdCAgICAgICAgICAgICAqICAgICAgICAgfVxuXHQgICAgICAgICAgICAgKiAgICAgfSk7XG5cdCAgICAgICAgICAgICAqL1xuXHQgICAgICAgICAgICBpbml0OiBmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgICAgIH0sXG5cblx0ICAgICAgICAgICAgLyoqXG5cdCAgICAgICAgICAgICAqIENvcGllcyBwcm9wZXJ0aWVzIGludG8gdGhpcyBvYmplY3QuXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwcm9wZXJ0aWVzIFRoZSBwcm9wZXJ0aWVzIHRvIG1peCBpbi5cblx0ICAgICAgICAgICAgICpcblx0ICAgICAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgICAgICpcblx0ICAgICAgICAgICAgICogICAgIE15VHlwZS5taXhJbih7XG5cdCAgICAgICAgICAgICAqICAgICAgICAgZmllbGQ6ICd2YWx1ZSdcblx0ICAgICAgICAgICAgICogICAgIH0pO1xuXHQgICAgICAgICAgICAgKi9cblx0ICAgICAgICAgICAgbWl4SW46IGZ1bmN0aW9uIChwcm9wZXJ0aWVzKSB7XG5cdCAgICAgICAgICAgICAgICBmb3IgKHZhciBwcm9wZXJ0eU5hbWUgaW4gcHJvcGVydGllcykge1xuXHQgICAgICAgICAgICAgICAgICAgIGlmIChwcm9wZXJ0aWVzLmhhc093blByb3BlcnR5KHByb3BlcnR5TmFtZSkpIHtcblx0ICAgICAgICAgICAgICAgICAgICAgICAgdGhpc1twcm9wZXJ0eU5hbWVdID0gcHJvcGVydGllc1twcm9wZXJ0eU5hbWVdO1xuXHQgICAgICAgICAgICAgICAgICAgIH1cblx0ICAgICAgICAgICAgICAgIH1cblxuXHQgICAgICAgICAgICAgICAgLy8gSUUgd29uJ3QgY29weSB0b1N0cmluZyB1c2luZyB0aGUgbG9vcCBhYm92ZVxuXHQgICAgICAgICAgICAgICAgaWYgKHByb3BlcnRpZXMuaGFzT3duUHJvcGVydHkoJ3RvU3RyaW5nJykpIHtcblx0ICAgICAgICAgICAgICAgICAgICB0aGlzLnRvU3RyaW5nID0gcHJvcGVydGllcy50b1N0cmluZztcblx0ICAgICAgICAgICAgICAgIH1cblx0ICAgICAgICAgICAgfSxcblxuXHQgICAgICAgICAgICAvKipcblx0ICAgICAgICAgICAgICogQ3JlYXRlcyBhIGNvcHkgb2YgdGhpcyBvYmplY3QuXG5cdCAgICAgICAgICAgICAqXG5cdCAgICAgICAgICAgICAqIEByZXR1cm4ge09iamVjdH0gVGhlIGNsb25lLlxuXHQgICAgICAgICAgICAgKlxuXHQgICAgICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAgICAgKlxuXHQgICAgICAgICAgICAgKiAgICAgdmFyIGNsb25lID0gaW5zdGFuY2UuY2xvbmUoKTtcblx0ICAgICAgICAgICAgICovXG5cdCAgICAgICAgICAgIGNsb25lOiBmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5pbml0LnByb3RvdHlwZS5leHRlbmQodGhpcyk7XG5cdCAgICAgICAgICAgIH1cblx0ICAgICAgICB9O1xuXHQgICAgfSgpKTtcblxuXHQgICAgLyoqXG5cdCAgICAgKiBBbiBhcnJheSBvZiAzMi1iaXQgd29yZHMuXG5cdCAgICAgKlxuXHQgICAgICogQHByb3BlcnR5IHtBcnJheX0gd29yZHMgVGhlIGFycmF5IG9mIDMyLWJpdCB3b3Jkcy5cblx0ICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBzaWdCeXRlcyBUaGUgbnVtYmVyIG9mIHNpZ25pZmljYW50IGJ5dGVzIGluIHRoaXMgd29yZCBhcnJheS5cblx0ICAgICAqL1xuXHQgICAgdmFyIFdvcmRBcnJheSA9IENfbGliLldvcmRBcnJheSA9IEJhc2UuZXh0ZW5kKHtcblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBJbml0aWFsaXplcyBhIG5ld2x5IGNyZWF0ZWQgd29yZCBhcnJheS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IHdvcmRzIChPcHRpb25hbCkgQW4gYXJyYXkgb2YgMzItYml0IHdvcmRzLlxuXHQgICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBzaWdCeXRlcyAoT3B0aW9uYWwpIFRoZSBudW1iZXIgb2Ygc2lnbmlmaWNhbnQgYnl0ZXMgaW4gdGhlIHdvcmRzLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgd29yZEFycmF5ID0gQ3J5cHRvSlMubGliLldvcmRBcnJheS5jcmVhdGUoKTtcblx0ICAgICAgICAgKiAgICAgdmFyIHdvcmRBcnJheSA9IENyeXB0b0pTLmxpYi5Xb3JkQXJyYXkuY3JlYXRlKFsweDAwMDEwMjAzLCAweDA0MDUwNjA3XSk7XG5cdCAgICAgICAgICogICAgIHZhciB3b3JkQXJyYXkgPSBDcnlwdG9KUy5saWIuV29yZEFycmF5LmNyZWF0ZShbMHgwMDAxMDIwMywgMHgwNDA1MDYwN10sIDYpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIGluaXQ6IGZ1bmN0aW9uICh3b3Jkcywgc2lnQnl0ZXMpIHtcblx0ICAgICAgICAgICAgd29yZHMgPSB0aGlzLndvcmRzID0gd29yZHMgfHwgW107XG5cblx0ICAgICAgICAgICAgaWYgKHNpZ0J5dGVzICE9IHVuZGVmaW5lZCkge1xuXHQgICAgICAgICAgICAgICAgdGhpcy5zaWdCeXRlcyA9IHNpZ0J5dGVzO1xuXHQgICAgICAgICAgICB9IGVsc2Uge1xuXHQgICAgICAgICAgICAgICAgdGhpcy5zaWdCeXRlcyA9IHdvcmRzLmxlbmd0aCAqIDQ7XG5cdCAgICAgICAgICAgIH1cblx0ICAgICAgICB9LFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogQ29udmVydHMgdGhpcyB3b3JkIGFycmF5IHRvIGEgc3RyaW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtFbmNvZGVyfSBlbmNvZGVyIChPcHRpb25hbCkgVGhlIGVuY29kaW5nIHN0cmF0ZWd5IHRvIHVzZS4gRGVmYXVsdDogQ3J5cHRvSlMuZW5jLkhleFxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7c3RyaW5nfSBUaGUgc3RyaW5naWZpZWQgd29yZCBhcnJheS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIHN0cmluZyA9IHdvcmRBcnJheSArICcnO1xuXHQgICAgICAgICAqICAgICB2YXIgc3RyaW5nID0gd29yZEFycmF5LnRvU3RyaW5nKCk7XG5cdCAgICAgICAgICogICAgIHZhciBzdHJpbmcgPSB3b3JkQXJyYXkudG9TdHJpbmcoQ3J5cHRvSlMuZW5jLlV0ZjgpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIHRvU3RyaW5nOiBmdW5jdGlvbiAoZW5jb2Rlcikge1xuXHQgICAgICAgICAgICByZXR1cm4gKGVuY29kZXIgfHwgSGV4KS5zdHJpbmdpZnkodGhpcyk7XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIENvbmNhdGVuYXRlcyBhIHdvcmQgYXJyYXkgdG8gdGhpcyB3b3JkIGFycmF5LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtXb3JkQXJyYXl9IHdvcmRBcnJheSBUaGUgd29yZCBhcnJheSB0byBhcHBlbmQuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtXb3JkQXJyYXl9IFRoaXMgd29yZCBhcnJheS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgd29yZEFycmF5MS5jb25jYXQod29yZEFycmF5Mik7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgY29uY2F0OiBmdW5jdGlvbiAod29yZEFycmF5KSB7XG5cdCAgICAgICAgICAgIC8vIFNob3J0Y3V0c1xuXHQgICAgICAgICAgICB2YXIgdGhpc1dvcmRzID0gdGhpcy53b3Jkcztcblx0ICAgICAgICAgICAgdmFyIHRoYXRXb3JkcyA9IHdvcmRBcnJheS53b3Jkcztcblx0ICAgICAgICAgICAgdmFyIHRoaXNTaWdCeXRlcyA9IHRoaXMuc2lnQnl0ZXM7XG5cdCAgICAgICAgICAgIHZhciB0aGF0U2lnQnl0ZXMgPSB3b3JkQXJyYXkuc2lnQnl0ZXM7XG5cblx0ICAgICAgICAgICAgLy8gQ2xhbXAgZXhjZXNzIGJpdHNcblx0ICAgICAgICAgICAgdGhpcy5jbGFtcCgpO1xuXG5cdCAgICAgICAgICAgIC8vIENvbmNhdFxuXHQgICAgICAgICAgICBpZiAodGhpc1NpZ0J5dGVzICUgNCkge1xuXHQgICAgICAgICAgICAgICAgLy8gQ29weSBvbmUgYnl0ZSBhdCBhIHRpbWVcblx0ICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhhdFNpZ0J5dGVzOyBpKyspIHtcblx0ICAgICAgICAgICAgICAgICAgICB2YXIgdGhhdEJ5dGUgPSAodGhhdFdvcmRzW2kgPj4+IDJdID4+PiAoMjQgLSAoaSAlIDQpICogOCkpICYgMHhmZjtcblx0ICAgICAgICAgICAgICAgICAgICB0aGlzV29yZHNbKHRoaXNTaWdCeXRlcyArIGkpID4+PiAyXSB8PSB0aGF0Qnl0ZSA8PCAoMjQgLSAoKHRoaXNTaWdCeXRlcyArIGkpICUgNCkgKiA4KTtcblx0ICAgICAgICAgICAgICAgIH1cblx0ICAgICAgICAgICAgfSBlbHNlIHtcblx0ICAgICAgICAgICAgICAgIC8vIENvcHkgb25lIHdvcmQgYXQgYSB0aW1lXG5cdCAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoYXRTaWdCeXRlczsgaSArPSA0KSB7XG5cdCAgICAgICAgICAgICAgICAgICAgdGhpc1dvcmRzWyh0aGlzU2lnQnl0ZXMgKyBpKSA+Pj4gMl0gPSB0aGF0V29yZHNbaSA+Pj4gMl07XG5cdCAgICAgICAgICAgICAgICB9XG5cdCAgICAgICAgICAgIH1cblx0ICAgICAgICAgICAgdGhpcy5zaWdCeXRlcyArPSB0aGF0U2lnQnl0ZXM7XG5cblx0ICAgICAgICAgICAgLy8gQ2hhaW5hYmxlXG5cdCAgICAgICAgICAgIHJldHVybiB0aGlzO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBSZW1vdmVzIGluc2lnbmlmaWNhbnQgYml0cy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgd29yZEFycmF5LmNsYW1wKCk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgY2xhbXA6IGZ1bmN0aW9uICgpIHtcblx0ICAgICAgICAgICAgLy8gU2hvcnRjdXRzXG5cdCAgICAgICAgICAgIHZhciB3b3JkcyA9IHRoaXMud29yZHM7XG5cdCAgICAgICAgICAgIHZhciBzaWdCeXRlcyA9IHRoaXMuc2lnQnl0ZXM7XG5cblx0ICAgICAgICAgICAgLy8gQ2xhbXBcblx0ICAgICAgICAgICAgd29yZHNbc2lnQnl0ZXMgPj4+IDJdICY9IDB4ZmZmZmZmZmYgPDwgKDMyIC0gKHNpZ0J5dGVzICUgNCkgKiA4KTtcblx0ICAgICAgICAgICAgd29yZHMubGVuZ3RoID0gTWF0aC5jZWlsKHNpZ0J5dGVzIC8gNCk7XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIENyZWF0ZXMgYSBjb3B5IG9mIHRoaXMgd29yZCBhcnJheS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge1dvcmRBcnJheX0gVGhlIGNsb25lLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgY2xvbmUgPSB3b3JkQXJyYXkuY2xvbmUoKTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICBjbG9uZTogZnVuY3Rpb24gKCkge1xuXHQgICAgICAgICAgICB2YXIgY2xvbmUgPSBCYXNlLmNsb25lLmNhbGwodGhpcyk7XG5cdCAgICAgICAgICAgIGNsb25lLndvcmRzID0gdGhpcy53b3Jkcy5zbGljZSgwKTtcblxuXHQgICAgICAgICAgICByZXR1cm4gY2xvbmU7XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIENyZWF0ZXMgYSB3b3JkIGFycmF5IGZpbGxlZCB3aXRoIHJhbmRvbSBieXRlcy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBuQnl0ZXMgVGhlIG51bWJlciBvZiByYW5kb20gYnl0ZXMgdG8gZ2VuZXJhdGUuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtXb3JkQXJyYXl9IFRoZSByYW5kb20gd29yZCBhcnJheS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBzdGF0aWNcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIHdvcmRBcnJheSA9IENyeXB0b0pTLmxpYi5Xb3JkQXJyYXkucmFuZG9tKDE2KTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICByYW5kb206IGZ1bmN0aW9uIChuQnl0ZXMpIHtcblx0ICAgICAgICAgICAgdmFyIHdvcmRzID0gW107XG5cblx0ICAgICAgICAgICAgdmFyIHIgPSAoZnVuY3Rpb24gKG1fdykge1xuXHQgICAgICAgICAgICAgICAgdmFyIG1fdyA9IG1fdztcblx0ICAgICAgICAgICAgICAgIHZhciBtX3ogPSAweDNhZGU2OGIxO1xuXHQgICAgICAgICAgICAgICAgdmFyIG1hc2sgPSAweGZmZmZmZmZmO1xuXG5cdCAgICAgICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24gKCkge1xuXHQgICAgICAgICAgICAgICAgICAgIG1feiA9ICgweDkwNjkgKiAobV96ICYgMHhGRkZGKSArIChtX3ogPj4gMHgxMCkpICYgbWFzaztcblx0ICAgICAgICAgICAgICAgICAgICBtX3cgPSAoMHg0NjUwICogKG1fdyAmIDB4RkZGRikgKyAobV93ID4+IDB4MTApKSAmIG1hc2s7XG5cdCAgICAgICAgICAgICAgICAgICAgdmFyIHJlc3VsdCA9ICgobV96IDw8IDB4MTApICsgbV93KSAmIG1hc2s7XG5cdCAgICAgICAgICAgICAgICAgICAgcmVzdWx0IC89IDB4MTAwMDAwMDAwO1xuXHQgICAgICAgICAgICAgICAgICAgIHJlc3VsdCArPSAwLjU7XG5cdCAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdCAqIChNYXRoLnJhbmRvbSgpID4gLjUgPyAxIDogLTEpO1xuXHQgICAgICAgICAgICAgICAgfVxuXHQgICAgICAgICAgICB9KTtcblxuXHQgICAgICAgICAgICBmb3IgKHZhciBpID0gMCwgcmNhY2hlOyBpIDwgbkJ5dGVzOyBpICs9IDQpIHtcblx0ICAgICAgICAgICAgICAgIHZhciBfciA9IHIoKHJjYWNoZSB8fCBNYXRoLnJhbmRvbSgpKSAqIDB4MTAwMDAwMDAwKTtcblxuXHQgICAgICAgICAgICAgICAgcmNhY2hlID0gX3IoKSAqIDB4M2FkZTY3Yjc7XG5cdCAgICAgICAgICAgICAgICB3b3Jkcy5wdXNoKChfcigpICogMHgxMDAwMDAwMDApIHwgMCk7XG5cdCAgICAgICAgICAgIH1cblxuXHQgICAgICAgICAgICByZXR1cm4gbmV3IFdvcmRBcnJheS5pbml0KHdvcmRzLCBuQnl0ZXMpO1xuXHQgICAgICAgIH1cblx0ICAgIH0pO1xuXG5cdCAgICAvKipcblx0ICAgICAqIEVuY29kZXIgbmFtZXNwYWNlLlxuXHQgICAgICovXG5cdCAgICB2YXIgQ19lbmMgPSBDLmVuYyA9IHt9O1xuXG5cdCAgICAvKipcblx0ICAgICAqIEhleCBlbmNvZGluZyBzdHJhdGVneS5cblx0ICAgICAqL1xuXHQgICAgdmFyIEhleCA9IENfZW5jLkhleCA9IHtcblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDb252ZXJ0cyBhIHdvcmQgYXJyYXkgdG8gYSBoZXggc3RyaW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtXb3JkQXJyYXl9IHdvcmRBcnJheSBUaGUgd29yZCBhcnJheS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge3N0cmluZ30gVGhlIGhleCBzdHJpbmcuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAc3RhdGljXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciBoZXhTdHJpbmcgPSBDcnlwdG9KUy5lbmMuSGV4LnN0cmluZ2lmeSh3b3JkQXJyYXkpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIHN0cmluZ2lmeTogZnVuY3Rpb24gKHdvcmRBcnJheSkge1xuXHQgICAgICAgICAgICAvLyBTaG9ydGN1dHNcblx0ICAgICAgICAgICAgdmFyIHdvcmRzID0gd29yZEFycmF5LndvcmRzO1xuXHQgICAgICAgICAgICB2YXIgc2lnQnl0ZXMgPSB3b3JkQXJyYXkuc2lnQnl0ZXM7XG5cblx0ICAgICAgICAgICAgLy8gQ29udmVydFxuXHQgICAgICAgICAgICB2YXIgaGV4Q2hhcnMgPSBbXTtcblx0ICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzaWdCeXRlczsgaSsrKSB7XG5cdCAgICAgICAgICAgICAgICB2YXIgYml0ZSA9ICh3b3Jkc1tpID4+PiAyXSA+Pj4gKDI0IC0gKGkgJSA0KSAqIDgpKSAmIDB4ZmY7XG5cdCAgICAgICAgICAgICAgICBoZXhDaGFycy5wdXNoKChiaXRlID4+PiA0KS50b1N0cmluZygxNikpO1xuXHQgICAgICAgICAgICAgICAgaGV4Q2hhcnMucHVzaCgoYml0ZSAmIDB4MGYpLnRvU3RyaW5nKDE2KSk7XG5cdCAgICAgICAgICAgIH1cblxuXHQgICAgICAgICAgICByZXR1cm4gaGV4Q2hhcnMuam9pbignJyk7XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIENvbnZlcnRzIGEgaGV4IHN0cmluZyB0byBhIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gaGV4U3RyIFRoZSBoZXggc3RyaW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7V29yZEFycmF5fSBUaGUgd29yZCBhcnJheS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBzdGF0aWNcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIHdvcmRBcnJheSA9IENyeXB0b0pTLmVuYy5IZXgucGFyc2UoaGV4U3RyaW5nKTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICBwYXJzZTogZnVuY3Rpb24gKGhleFN0cikge1xuXHQgICAgICAgICAgICAvLyBTaG9ydGN1dFxuXHQgICAgICAgICAgICB2YXIgaGV4U3RyTGVuZ3RoID0gaGV4U3RyLmxlbmd0aDtcblxuXHQgICAgICAgICAgICAvLyBDb252ZXJ0XG5cdCAgICAgICAgICAgIHZhciB3b3JkcyA9IFtdO1xuXHQgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGhleFN0ckxlbmd0aDsgaSArPSAyKSB7XG5cdCAgICAgICAgICAgICAgICB3b3Jkc1tpID4+PiAzXSB8PSBwYXJzZUludChoZXhTdHIuc3Vic3RyKGksIDIpLCAxNikgPDwgKDI0IC0gKGkgJSA4KSAqIDQpO1xuXHQgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgcmV0dXJuIG5ldyBXb3JkQXJyYXkuaW5pdCh3b3JkcywgaGV4U3RyTGVuZ3RoIC8gMik7XG5cdCAgICAgICAgfVxuXHQgICAgfTtcblxuXHQgICAgLyoqXG5cdCAgICAgKiBMYXRpbjEgZW5jb2Rpbmcgc3RyYXRlZ3kuXG5cdCAgICAgKi9cblx0ICAgIHZhciBMYXRpbjEgPSBDX2VuYy5MYXRpbjEgPSB7XG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogQ29udmVydHMgYSB3b3JkIGFycmF5IHRvIGEgTGF0aW4xIHN0cmluZy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7V29yZEFycmF5fSB3b3JkQXJyYXkgVGhlIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBMYXRpbjEgc3RyaW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHN0YXRpY1xuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgbGF0aW4xU3RyaW5nID0gQ3J5cHRvSlMuZW5jLkxhdGluMS5zdHJpbmdpZnkod29yZEFycmF5KTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICBzdHJpbmdpZnk6IGZ1bmN0aW9uICh3b3JkQXJyYXkpIHtcblx0ICAgICAgICAgICAgLy8gU2hvcnRjdXRzXG5cdCAgICAgICAgICAgIHZhciB3b3JkcyA9IHdvcmRBcnJheS53b3Jkcztcblx0ICAgICAgICAgICAgdmFyIHNpZ0J5dGVzID0gd29yZEFycmF5LnNpZ0J5dGVzO1xuXG5cdCAgICAgICAgICAgIC8vIENvbnZlcnRcblx0ICAgICAgICAgICAgdmFyIGxhdGluMUNoYXJzID0gW107XG5cdCAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2lnQnl0ZXM7IGkrKykge1xuXHQgICAgICAgICAgICAgICAgdmFyIGJpdGUgPSAod29yZHNbaSA+Pj4gMl0gPj4+ICgyNCAtIChpICUgNCkgKiA4KSkgJiAweGZmO1xuXHQgICAgICAgICAgICAgICAgbGF0aW4xQ2hhcnMucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKGJpdGUpKTtcblx0ICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgIHJldHVybiBsYXRpbjFDaGFycy5qb2luKCcnKTtcblx0ICAgICAgICB9LFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogQ29udmVydHMgYSBMYXRpbjEgc3RyaW5nIHRvIGEgd29yZCBhcnJheS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBsYXRpbjFTdHIgVGhlIExhdGluMSBzdHJpbmcuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtXb3JkQXJyYXl9IFRoZSB3b3JkIGFycmF5LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHN0YXRpY1xuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgd29yZEFycmF5ID0gQ3J5cHRvSlMuZW5jLkxhdGluMS5wYXJzZShsYXRpbjFTdHJpbmcpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIHBhcnNlOiBmdW5jdGlvbiAobGF0aW4xU3RyKSB7XG5cdCAgICAgICAgICAgIC8vIFNob3J0Y3V0XG5cdCAgICAgICAgICAgIHZhciBsYXRpbjFTdHJMZW5ndGggPSBsYXRpbjFTdHIubGVuZ3RoO1xuXG5cdCAgICAgICAgICAgIC8vIENvbnZlcnRcblx0ICAgICAgICAgICAgdmFyIHdvcmRzID0gW107XG5cdCAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGF0aW4xU3RyTGVuZ3RoOyBpKyspIHtcblx0ICAgICAgICAgICAgICAgIHdvcmRzW2kgPj4+IDJdIHw9IChsYXRpbjFTdHIuY2hhckNvZGVBdChpKSAmIDB4ZmYpIDw8ICgyNCAtIChpICUgNCkgKiA4KTtcblx0ICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgIHJldHVybiBuZXcgV29yZEFycmF5LmluaXQod29yZHMsIGxhdGluMVN0ckxlbmd0aCk7XG5cdCAgICAgICAgfVxuXHQgICAgfTtcblxuXHQgICAgLyoqXG5cdCAgICAgKiBVVEYtOCBlbmNvZGluZyBzdHJhdGVneS5cblx0ICAgICAqL1xuXHQgICAgdmFyIFV0ZjggPSBDX2VuYy5VdGY4ID0ge1xuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIENvbnZlcnRzIGEgd29yZCBhcnJheSB0byBhIFVURi04IHN0cmluZy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7V29yZEFycmF5fSB3b3JkQXJyYXkgVGhlIHdvcmQgYXJyYXkuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBVVEYtOCBzdHJpbmcuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAc3RhdGljXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciB1dGY4U3RyaW5nID0gQ3J5cHRvSlMuZW5jLlV0Zjguc3RyaW5naWZ5KHdvcmRBcnJheSk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgc3RyaW5naWZ5OiBmdW5jdGlvbiAod29yZEFycmF5KSB7XG5cdCAgICAgICAgICAgIHRyeSB7XG5cdCAgICAgICAgICAgICAgICByZXR1cm4gZGVjb2RlVVJJQ29tcG9uZW50KGVzY2FwZShMYXRpbjEuc3RyaW5naWZ5KHdvcmRBcnJheSkpKTtcblx0ICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuXHQgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdNYWxmb3JtZWQgVVRGLTggZGF0YScpO1xuXHQgICAgICAgICAgICB9XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIENvbnZlcnRzIGEgVVRGLTggc3RyaW5nIHRvIGEgd29yZCBhcnJheS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSB1dGY4U3RyIFRoZSBVVEYtOCBzdHJpbmcuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtXb3JkQXJyYXl9IFRoZSB3b3JkIGFycmF5LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHN0YXRpY1xuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgd29yZEFycmF5ID0gQ3J5cHRvSlMuZW5jLlV0ZjgucGFyc2UodXRmOFN0cmluZyk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgcGFyc2U6IGZ1bmN0aW9uICh1dGY4U3RyKSB7XG5cdCAgICAgICAgICAgIHJldHVybiBMYXRpbjEucGFyc2UodW5lc2NhcGUoZW5jb2RlVVJJQ29tcG9uZW50KHV0ZjhTdHIpKSk7XG5cdCAgICAgICAgfVxuXHQgICAgfTtcblxuXHQgICAgLyoqXG5cdCAgICAgKiBBYnN0cmFjdCBidWZmZXJlZCBibG9jayBhbGdvcml0aG0gdGVtcGxhdGUuXG5cdCAgICAgKlxuXHQgICAgICogVGhlIHByb3BlcnR5IGJsb2NrU2l6ZSBtdXN0IGJlIGltcGxlbWVudGVkIGluIGEgY29uY3JldGUgc3VidHlwZS5cblx0ICAgICAqXG5cdCAgICAgKiBAcHJvcGVydHkge251bWJlcn0gX21pbkJ1ZmZlclNpemUgVGhlIG51bWJlciBvZiBibG9ja3MgdGhhdCBzaG91bGQgYmUga2VwdCB1bnByb2Nlc3NlZCBpbiB0aGUgYnVmZmVyLiBEZWZhdWx0OiAwXG5cdCAgICAgKi9cblx0ICAgIHZhciBCdWZmZXJlZEJsb2NrQWxnb3JpdGhtID0gQ19saWIuQnVmZmVyZWRCbG9ja0FsZ29yaXRobSA9IEJhc2UuZXh0ZW5kKHtcblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBSZXNldHMgdGhpcyBibG9jayBhbGdvcml0aG0ncyBkYXRhIGJ1ZmZlciB0byBpdHMgaW5pdGlhbCBzdGF0ZS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgYnVmZmVyZWRCbG9ja0FsZ29yaXRobS5yZXNldCgpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIHJlc2V0OiBmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgICAgIC8vIEluaXRpYWwgdmFsdWVzXG5cdCAgICAgICAgICAgIHRoaXMuX2RhdGEgPSBuZXcgV29yZEFycmF5LmluaXQoKTtcblx0ICAgICAgICAgICAgdGhpcy5fbkRhdGFCeXRlcyA9IDA7XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIEFkZHMgbmV3IGRhdGEgdG8gdGhpcyBibG9jayBhbGdvcml0aG0ncyBidWZmZXIuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge1dvcmRBcnJheXxzdHJpbmd9IGRhdGEgVGhlIGRhdGEgdG8gYXBwZW5kLiBTdHJpbmdzIGFyZSBjb252ZXJ0ZWQgdG8gYSBXb3JkQXJyYXkgdXNpbmcgVVRGLTguXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIGJ1ZmZlcmVkQmxvY2tBbGdvcml0aG0uX2FwcGVuZCgnZGF0YScpO1xuXHQgICAgICAgICAqICAgICBidWZmZXJlZEJsb2NrQWxnb3JpdGhtLl9hcHBlbmQod29yZEFycmF5KTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICBfYXBwZW5kOiBmdW5jdGlvbiAoZGF0YSkge1xuXHQgICAgICAgICAgICAvLyBDb252ZXJ0IHN0cmluZyB0byBXb3JkQXJyYXksIGVsc2UgYXNzdW1lIFdvcmRBcnJheSBhbHJlYWR5XG5cdCAgICAgICAgICAgIGlmICh0eXBlb2YgZGF0YSA9PSAnc3RyaW5nJykge1xuXHQgICAgICAgICAgICAgICAgZGF0YSA9IFV0ZjgucGFyc2UoZGF0YSk7XG5cdCAgICAgICAgICAgIH1cblxuXHQgICAgICAgICAgICAvLyBBcHBlbmRcblx0ICAgICAgICAgICAgdGhpcy5fZGF0YS5jb25jYXQoZGF0YSk7XG5cdCAgICAgICAgICAgIHRoaXMuX25EYXRhQnl0ZXMgKz0gZGF0YS5zaWdCeXRlcztcblx0ICAgICAgICB9LFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogUHJvY2Vzc2VzIGF2YWlsYWJsZSBkYXRhIGJsb2Nrcy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIFRoaXMgbWV0aG9kIGludm9rZXMgX2RvUHJvY2Vzc0Jsb2NrKG9mZnNldCksIHdoaWNoIG11c3QgYmUgaW1wbGVtZW50ZWQgYnkgYSBjb25jcmV0ZSBzdWJ0eXBlLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtib29sZWFufSBkb0ZsdXNoIFdoZXRoZXIgYWxsIGJsb2NrcyBhbmQgcGFydGlhbCBibG9ja3Mgc2hvdWxkIGJlIHByb2Nlc3NlZC5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge1dvcmRBcnJheX0gVGhlIHByb2Nlc3NlZCBkYXRhLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgcHJvY2Vzc2VkRGF0YSA9IGJ1ZmZlcmVkQmxvY2tBbGdvcml0aG0uX3Byb2Nlc3MoKTtcblx0ICAgICAgICAgKiAgICAgdmFyIHByb2Nlc3NlZERhdGEgPSBidWZmZXJlZEJsb2NrQWxnb3JpdGhtLl9wcm9jZXNzKCEhJ2ZsdXNoJyk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgX3Byb2Nlc3M6IGZ1bmN0aW9uIChkb0ZsdXNoKSB7XG5cdCAgICAgICAgICAgIC8vIFNob3J0Y3V0c1xuXHQgICAgICAgICAgICB2YXIgZGF0YSA9IHRoaXMuX2RhdGE7XG5cdCAgICAgICAgICAgIHZhciBkYXRhV29yZHMgPSBkYXRhLndvcmRzO1xuXHQgICAgICAgICAgICB2YXIgZGF0YVNpZ0J5dGVzID0gZGF0YS5zaWdCeXRlcztcblx0ICAgICAgICAgICAgdmFyIGJsb2NrU2l6ZSA9IHRoaXMuYmxvY2tTaXplO1xuXHQgICAgICAgICAgICB2YXIgYmxvY2tTaXplQnl0ZXMgPSBibG9ja1NpemUgKiA0O1xuXG5cdCAgICAgICAgICAgIC8vIENvdW50IGJsb2NrcyByZWFkeVxuXHQgICAgICAgICAgICB2YXIgbkJsb2Nrc1JlYWR5ID0gZGF0YVNpZ0J5dGVzIC8gYmxvY2tTaXplQnl0ZXM7XG5cdCAgICAgICAgICAgIGlmIChkb0ZsdXNoKSB7XG5cdCAgICAgICAgICAgICAgICAvLyBSb3VuZCB1cCB0byBpbmNsdWRlIHBhcnRpYWwgYmxvY2tzXG5cdCAgICAgICAgICAgICAgICBuQmxvY2tzUmVhZHkgPSBNYXRoLmNlaWwobkJsb2Nrc1JlYWR5KTtcblx0ICAgICAgICAgICAgfSBlbHNlIHtcblx0ICAgICAgICAgICAgICAgIC8vIFJvdW5kIGRvd24gdG8gaW5jbHVkZSBvbmx5IGZ1bGwgYmxvY2tzLFxuXHQgICAgICAgICAgICAgICAgLy8gbGVzcyB0aGUgbnVtYmVyIG9mIGJsb2NrcyB0aGF0IG11c3QgcmVtYWluIGluIHRoZSBidWZmZXJcblx0ICAgICAgICAgICAgICAgIG5CbG9ja3NSZWFkeSA9IE1hdGgubWF4KChuQmxvY2tzUmVhZHkgfCAwKSAtIHRoaXMuX21pbkJ1ZmZlclNpemUsIDApO1xuXHQgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgLy8gQ291bnQgd29yZHMgcmVhZHlcblx0ICAgICAgICAgICAgdmFyIG5Xb3Jkc1JlYWR5ID0gbkJsb2Nrc1JlYWR5ICogYmxvY2tTaXplO1xuXG5cdCAgICAgICAgICAgIC8vIENvdW50IGJ5dGVzIHJlYWR5XG5cdCAgICAgICAgICAgIHZhciBuQnl0ZXNSZWFkeSA9IE1hdGgubWluKG5Xb3Jkc1JlYWR5ICogNCwgZGF0YVNpZ0J5dGVzKTtcblxuXHQgICAgICAgICAgICAvLyBQcm9jZXNzIGJsb2Nrc1xuXHQgICAgICAgICAgICBpZiAobldvcmRzUmVhZHkpIHtcblx0ICAgICAgICAgICAgICAgIGZvciAodmFyIG9mZnNldCA9IDA7IG9mZnNldCA8IG5Xb3Jkc1JlYWR5OyBvZmZzZXQgKz0gYmxvY2tTaXplKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgLy8gUGVyZm9ybSBjb25jcmV0ZS1hbGdvcml0aG0gbG9naWNcblx0ICAgICAgICAgICAgICAgICAgICB0aGlzLl9kb1Byb2Nlc3NCbG9jayhkYXRhV29yZHMsIG9mZnNldCk7XG5cdCAgICAgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgICAgIC8vIFJlbW92ZSBwcm9jZXNzZWQgd29yZHNcblx0ICAgICAgICAgICAgICAgIHZhciBwcm9jZXNzZWRXb3JkcyA9IGRhdGFXb3Jkcy5zcGxpY2UoMCwgbldvcmRzUmVhZHkpO1xuXHQgICAgICAgICAgICAgICAgZGF0YS5zaWdCeXRlcyAtPSBuQnl0ZXNSZWFkeTtcblx0ICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgIC8vIFJldHVybiBwcm9jZXNzZWQgd29yZHNcblx0ICAgICAgICAgICAgcmV0dXJuIG5ldyBXb3JkQXJyYXkuaW5pdChwcm9jZXNzZWRXb3JkcywgbkJ5dGVzUmVhZHkpO1xuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDcmVhdGVzIGEgY29weSBvZiB0aGlzIG9iamVjdC5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge09iamVjdH0gVGhlIGNsb25lLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgY2xvbmUgPSBidWZmZXJlZEJsb2NrQWxnb3JpdGhtLmNsb25lKCk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgY2xvbmU6IGZ1bmN0aW9uICgpIHtcblx0ICAgICAgICAgICAgdmFyIGNsb25lID0gQmFzZS5jbG9uZS5jYWxsKHRoaXMpO1xuXHQgICAgICAgICAgICBjbG9uZS5fZGF0YSA9IHRoaXMuX2RhdGEuY2xvbmUoKTtcblxuXHQgICAgICAgICAgICByZXR1cm4gY2xvbmU7XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIF9taW5CdWZmZXJTaXplOiAwXG5cdCAgICB9KTtcblxuXHQgICAgLyoqXG5cdCAgICAgKiBBYnN0cmFjdCBoYXNoZXIgdGVtcGxhdGUuXG5cdCAgICAgKlxuXHQgICAgICogQHByb3BlcnR5IHtudW1iZXJ9IGJsb2NrU2l6ZSBUaGUgbnVtYmVyIG9mIDMyLWJpdCB3b3JkcyB0aGlzIGhhc2hlciBvcGVyYXRlcyBvbi4gRGVmYXVsdDogMTYgKDUxMiBiaXRzKVxuXHQgICAgICovXG5cdCAgICB2YXIgSGFzaGVyID0gQ19saWIuSGFzaGVyID0gQnVmZmVyZWRCbG9ja0FsZ29yaXRobS5leHRlbmQoe1xuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIENvbmZpZ3VyYXRpb24gb3B0aW9ucy5cblx0ICAgICAgICAgKi9cblx0ICAgICAgICBjZmc6IEJhc2UuZXh0ZW5kKCksXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBJbml0aWFsaXplcyBhIG5ld2x5IGNyZWF0ZWQgaGFzaGVyLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IGNmZyAoT3B0aW9uYWwpIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gdXNlIGZvciB0aGlzIGhhc2ggY29tcHV0YXRpb24uXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciBoYXNoZXIgPSBDcnlwdG9KUy5hbGdvLlNIQTI1Ni5jcmVhdGUoKTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICBpbml0OiBmdW5jdGlvbiAoY2ZnKSB7XG5cdCAgICAgICAgICAgIC8vIEFwcGx5IGNvbmZpZyBkZWZhdWx0c1xuXHQgICAgICAgICAgICB0aGlzLmNmZyA9IHRoaXMuY2ZnLmV4dGVuZChjZmcpO1xuXG5cdCAgICAgICAgICAgIC8vIFNldCBpbml0aWFsIHZhbHVlc1xuXHQgICAgICAgICAgICB0aGlzLnJlc2V0KCk7XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIFJlc2V0cyB0aGlzIGhhc2hlciB0byBpdHMgaW5pdGlhbCBzdGF0ZS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgaGFzaGVyLnJlc2V0KCk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgcmVzZXQ6IGZ1bmN0aW9uICgpIHtcblx0ICAgICAgICAgICAgLy8gUmVzZXQgZGF0YSBidWZmZXJcblx0ICAgICAgICAgICAgQnVmZmVyZWRCbG9ja0FsZ29yaXRobS5yZXNldC5jYWxsKHRoaXMpO1xuXG5cdCAgICAgICAgICAgIC8vIFBlcmZvcm0gY29uY3JldGUtaGFzaGVyIGxvZ2ljXG5cdCAgICAgICAgICAgIHRoaXMuX2RvUmVzZXQoKTtcblx0ICAgICAgICB9LFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogVXBkYXRlcyB0aGlzIGhhc2hlciB3aXRoIGEgbWVzc2FnZS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7V29yZEFycmF5fHN0cmluZ30gbWVzc2FnZVVwZGF0ZSBUaGUgbWVzc2FnZSB0byBhcHBlbmQuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtIYXNoZXJ9IFRoaXMgaGFzaGVyLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICBoYXNoZXIudXBkYXRlKCdtZXNzYWdlJyk7XG5cdCAgICAgICAgICogICAgIGhhc2hlci51cGRhdGUod29yZEFycmF5KTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICB1cGRhdGU6IGZ1bmN0aW9uIChtZXNzYWdlVXBkYXRlKSB7XG5cdCAgICAgICAgICAgIC8vIEFwcGVuZFxuXHQgICAgICAgICAgICB0aGlzLl9hcHBlbmQobWVzc2FnZVVwZGF0ZSk7XG5cblx0ICAgICAgICAgICAgLy8gVXBkYXRlIHRoZSBoYXNoXG5cdCAgICAgICAgICAgIHRoaXMuX3Byb2Nlc3MoKTtcblxuXHQgICAgICAgICAgICAvLyBDaGFpbmFibGVcblx0ICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIEZpbmFsaXplcyB0aGUgaGFzaCBjb21wdXRhdGlvbi5cblx0ICAgICAgICAgKiBOb3RlIHRoYXQgdGhlIGZpbmFsaXplIG9wZXJhdGlvbiBpcyBlZmZlY3RpdmVseSBhIGRlc3RydWN0aXZlLCByZWFkLW9uY2Ugb3BlcmF0aW9uLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtXb3JkQXJyYXl8c3RyaW5nfSBtZXNzYWdlVXBkYXRlIChPcHRpb25hbCkgQSBmaW5hbCBtZXNzYWdlIHVwZGF0ZS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge1dvcmRBcnJheX0gVGhlIGhhc2guXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciBoYXNoID0gaGFzaGVyLmZpbmFsaXplKCk7XG5cdCAgICAgICAgICogICAgIHZhciBoYXNoID0gaGFzaGVyLmZpbmFsaXplKCdtZXNzYWdlJyk7XG5cdCAgICAgICAgICogICAgIHZhciBoYXNoID0gaGFzaGVyLmZpbmFsaXplKHdvcmRBcnJheSk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgZmluYWxpemU6IGZ1bmN0aW9uIChtZXNzYWdlVXBkYXRlKSB7XG5cdCAgICAgICAgICAgIC8vIEZpbmFsIG1lc3NhZ2UgdXBkYXRlXG5cdCAgICAgICAgICAgIGlmIChtZXNzYWdlVXBkYXRlKSB7XG5cdCAgICAgICAgICAgICAgICB0aGlzLl9hcHBlbmQobWVzc2FnZVVwZGF0ZSk7XG5cdCAgICAgICAgICAgIH1cblxuXHQgICAgICAgICAgICAvLyBQZXJmb3JtIGNvbmNyZXRlLWhhc2hlciBsb2dpY1xuXHQgICAgICAgICAgICB2YXIgaGFzaCA9IHRoaXMuX2RvRmluYWxpemUoKTtcblxuXHQgICAgICAgICAgICByZXR1cm4gaGFzaDtcblx0ICAgICAgICB9LFxuXG5cdCAgICAgICAgYmxvY2tTaXplOiA1MTIvMzIsXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBDcmVhdGVzIGEgc2hvcnRjdXQgZnVuY3Rpb24gdG8gYSBoYXNoZXIncyBvYmplY3QgaW50ZXJmYWNlLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtIYXNoZXJ9IGhhc2hlciBUaGUgaGFzaGVyIHRvIGNyZWF0ZSBhIGhlbHBlciBmb3IuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtGdW5jdGlvbn0gVGhlIHNob3J0Y3V0IGZ1bmN0aW9uLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHN0YXRpY1xuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgU0hBMjU2ID0gQ3J5cHRvSlMubGliLkhhc2hlci5fY3JlYXRlSGVscGVyKENyeXB0b0pTLmFsZ28uU0hBMjU2KTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICBfY3JlYXRlSGVscGVyOiBmdW5jdGlvbiAoaGFzaGVyKSB7XG5cdCAgICAgICAgICAgIHJldHVybiBmdW5jdGlvbiAobWVzc2FnZSwgY2ZnKSB7XG5cdCAgICAgICAgICAgICAgICByZXR1cm4gbmV3IGhhc2hlci5pbml0KGNmZykuZmluYWxpemUobWVzc2FnZSk7XG5cdCAgICAgICAgICAgIH07XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIENyZWF0ZXMgYSBzaG9ydGN1dCBmdW5jdGlvbiB0byB0aGUgSE1BQydzIG9iamVjdCBpbnRlcmZhY2UuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge0hhc2hlcn0gaGFzaGVyIFRoZSBoYXNoZXIgdG8gdXNlIGluIHRoaXMgSE1BQyBoZWxwZXIuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtGdW5jdGlvbn0gVGhlIHNob3J0Y3V0IGZ1bmN0aW9uLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHN0YXRpY1xuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgSG1hY1NIQTI1NiA9IENyeXB0b0pTLmxpYi5IYXNoZXIuX2NyZWF0ZUhtYWNIZWxwZXIoQ3J5cHRvSlMuYWxnby5TSEEyNTYpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIF9jcmVhdGVIbWFjSGVscGVyOiBmdW5jdGlvbiAoaGFzaGVyKSB7XG5cdCAgICAgICAgICAgIHJldHVybiBmdW5jdGlvbiAobWVzc2FnZSwga2V5KSB7XG5cdCAgICAgICAgICAgICAgICByZXR1cm4gbmV3IENfYWxnby5ITUFDLmluaXQoaGFzaGVyLCBrZXkpLmZpbmFsaXplKG1lc3NhZ2UpO1xuXHQgICAgICAgICAgICB9O1xuXHQgICAgICAgIH1cblx0ICAgIH0pO1xuXG5cdCAgICAvKipcblx0ICAgICAqIEFsZ29yaXRobSBuYW1lc3BhY2UuXG5cdCAgICAgKi9cblx0ICAgIHZhciBDX2FsZ28gPSBDLmFsZ28gPSB7fTtcblxuXHQgICAgcmV0dXJuIEM7XG5cdH0oTWF0aCkpO1xuXG5cblx0cmV0dXJuIENyeXB0b0pTO1xuXG59KSk7IiwiOyhmdW5jdGlvbiAocm9vdCwgZmFjdG9yeSwgdW5kZWYpIHtcblx0aWYgKHR5cGVvZiBleHBvcnRzID09PSBcIm9iamVjdFwiKSB7XG5cdFx0Ly8gQ29tbW9uSlNcblx0XHRtb2R1bGUuZXhwb3J0cyA9IGV4cG9ydHMgPSBmYWN0b3J5KHJlcXVpcmUoXCIuL2NvcmVcIiksIHJlcXVpcmUoXCIuL3g2NC1jb3JlXCIpKTtcblx0fVxuXHRlbHNlIGlmICh0eXBlb2YgZGVmaW5lID09PSBcImZ1bmN0aW9uXCIgJiYgZGVmaW5lLmFtZCkge1xuXHRcdC8vIEFNRFxuXHRcdGRlZmluZShbXCIuL2NvcmVcIiwgXCIuL3g2NC1jb3JlXCJdLCBmYWN0b3J5KTtcblx0fVxuXHRlbHNlIHtcblx0XHQvLyBHbG9iYWwgKGJyb3dzZXIpXG5cdFx0ZmFjdG9yeShyb290LkNyeXB0b0pTKTtcblx0fVxufSh0aGlzLCBmdW5jdGlvbiAoQ3J5cHRvSlMpIHtcblxuXHQoZnVuY3Rpb24gKE1hdGgpIHtcblx0ICAgIC8vIFNob3J0Y3V0c1xuXHQgICAgdmFyIEMgPSBDcnlwdG9KUztcblx0ICAgIHZhciBDX2xpYiA9IEMubGliO1xuXHQgICAgdmFyIFdvcmRBcnJheSA9IENfbGliLldvcmRBcnJheTtcblx0ICAgIHZhciBIYXNoZXIgPSBDX2xpYi5IYXNoZXI7XG5cdCAgICB2YXIgQ194NjQgPSBDLng2NDtcblx0ICAgIHZhciBYNjRXb3JkID0gQ194NjQuV29yZDtcblx0ICAgIHZhciBDX2FsZ28gPSBDLmFsZ287XG5cblx0ICAgIC8vIENvbnN0YW50cyB0YWJsZXNcblx0ICAgIHZhciBSSE9fT0ZGU0VUUyA9IFtdO1xuXHQgICAgdmFyIFBJX0lOREVYRVMgID0gW107XG5cdCAgICB2YXIgUk9VTkRfQ09OU1RBTlRTID0gW107XG5cblx0ICAgIC8vIENvbXB1dGUgQ29uc3RhbnRzXG5cdCAgICAoZnVuY3Rpb24gKCkge1xuXHQgICAgICAgIC8vIENvbXB1dGUgcmhvIG9mZnNldCBjb25zdGFudHNcblx0ICAgICAgICB2YXIgeCA9IDEsIHkgPSAwO1xuXHQgICAgICAgIGZvciAodmFyIHQgPSAwOyB0IDwgMjQ7IHQrKykge1xuXHQgICAgICAgICAgICBSSE9fT0ZGU0VUU1t4ICsgNSAqIHldID0gKCh0ICsgMSkgKiAodCArIDIpIC8gMikgJSA2NDtcblxuXHQgICAgICAgICAgICB2YXIgbmV3WCA9IHkgJSA1O1xuXHQgICAgICAgICAgICB2YXIgbmV3WSA9ICgyICogeCArIDMgKiB5KSAlIDU7XG5cdCAgICAgICAgICAgIHggPSBuZXdYO1xuXHQgICAgICAgICAgICB5ID0gbmV3WTtcblx0ICAgICAgICB9XG5cblx0ICAgICAgICAvLyBDb21wdXRlIHBpIGluZGV4IGNvbnN0YW50c1xuXHQgICAgICAgIGZvciAodmFyIHggPSAwOyB4IDwgNTsgeCsrKSB7XG5cdCAgICAgICAgICAgIGZvciAodmFyIHkgPSAwOyB5IDwgNTsgeSsrKSB7XG5cdCAgICAgICAgICAgICAgICBQSV9JTkRFWEVTW3ggKyA1ICogeV0gPSB5ICsgKCgyICogeCArIDMgKiB5KSAlIDUpICogNTtcblx0ICAgICAgICAgICAgfVxuXHQgICAgICAgIH1cblxuXHQgICAgICAgIC8vIENvbXB1dGUgcm91bmQgY29uc3RhbnRzXG5cdCAgICAgICAgdmFyIExGU1IgPSAweDAxO1xuXHQgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgMjQ7IGkrKykge1xuXHQgICAgICAgICAgICB2YXIgcm91bmRDb25zdGFudE1zdyA9IDA7XG5cdCAgICAgICAgICAgIHZhciByb3VuZENvbnN0YW50THN3ID0gMDtcblxuXHQgICAgICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IDc7IGorKykge1xuXHQgICAgICAgICAgICAgICAgaWYgKExGU1IgJiAweDAxKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgdmFyIGJpdFBvc2l0aW9uID0gKDEgPDwgaikgLSAxO1xuXHQgICAgICAgICAgICAgICAgICAgIGlmIChiaXRQb3NpdGlvbiA8IDMyKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIHJvdW5kQ29uc3RhbnRMc3cgXj0gMSA8PCBiaXRQb3NpdGlvbjtcblx0ICAgICAgICAgICAgICAgICAgICB9IGVsc2UgLyogaWYgKGJpdFBvc2l0aW9uID49IDMyKSAqLyB7XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIHJvdW5kQ29uc3RhbnRNc3cgXj0gMSA8PCAoYml0UG9zaXRpb24gLSAzMik7XG5cdCAgICAgICAgICAgICAgICAgICAgfVxuXHQgICAgICAgICAgICAgICAgfVxuXG5cdCAgICAgICAgICAgICAgICAvLyBDb21wdXRlIG5leHQgTEZTUlxuXHQgICAgICAgICAgICAgICAgaWYgKExGU1IgJiAweDgwKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgLy8gUHJpbWl0aXZlIHBvbHlub21pYWwgb3ZlciBHRigyKTogeF44ICsgeF42ICsgeF41ICsgeF40ICsgMVxuXHQgICAgICAgICAgICAgICAgICAgIExGU1IgPSAoTEZTUiA8PCAxKSBeIDB4NzE7XG5cdCAgICAgICAgICAgICAgICB9IGVsc2Uge1xuXHQgICAgICAgICAgICAgICAgICAgIExGU1IgPDw9IDE7XG5cdCAgICAgICAgICAgICAgICB9XG5cdCAgICAgICAgICAgIH1cblxuXHQgICAgICAgICAgICBST1VORF9DT05TVEFOVFNbaV0gPSBYNjRXb3JkLmNyZWF0ZShyb3VuZENvbnN0YW50TXN3LCByb3VuZENvbnN0YW50THN3KTtcblx0ICAgICAgICB9XG5cdCAgICB9KCkpO1xuXG5cdCAgICAvLyBSZXVzYWJsZSBvYmplY3RzIGZvciB0ZW1wb3JhcnkgdmFsdWVzXG5cdCAgICB2YXIgVCA9IFtdO1xuXHQgICAgKGZ1bmN0aW9uICgpIHtcblx0ICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IDI1OyBpKyspIHtcblx0ICAgICAgICAgICAgVFtpXSA9IFg2NFdvcmQuY3JlYXRlKCk7XG5cdCAgICAgICAgfVxuXHQgICAgfSgpKTtcblxuXHQgICAgLyoqXG5cdCAgICAgKiBTSEEtMyBoYXNoIGFsZ29yaXRobS5cblx0ICAgICAqL1xuXHQgICAgdmFyIFNIQTMgPSBDX2FsZ28uU0hBMyA9IEhhc2hlci5leHRlbmQoe1xuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIENvbmZpZ3VyYXRpb24gb3B0aW9ucy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBvdXRwdXRMZW5ndGhcblx0ICAgICAgICAgKiAgIFRoZSBkZXNpcmVkIG51bWJlciBvZiBiaXRzIGluIHRoZSBvdXRwdXQgaGFzaC5cblx0ICAgICAgICAgKiAgIE9ubHkgdmFsdWVzIHBlcm1pdHRlZCBhcmU6IDIyNCwgMjU2LCAzODQsIDUxMi5cblx0ICAgICAgICAgKiAgIERlZmF1bHQ6IDUxMlxuXHQgICAgICAgICAqL1xuXHQgICAgICAgIGNmZzogSGFzaGVyLmNmZy5leHRlbmQoe1xuXHQgICAgICAgICAgICBvdXRwdXRMZW5ndGg6IDUxMlxuXHQgICAgICAgIH0pLFxuXG5cdCAgICAgICAgX2RvUmVzZXQ6IGZ1bmN0aW9uICgpIHtcblx0ICAgICAgICAgICAgdmFyIHN0YXRlID0gdGhpcy5fc3RhdGUgPSBbXVxuXHQgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IDI1OyBpKyspIHtcblx0ICAgICAgICAgICAgICAgIHN0YXRlW2ldID0gbmV3IFg2NFdvcmQuaW5pdCgpO1xuXHQgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgdGhpcy5ibG9ja1NpemUgPSAoMTYwMCAtIDIgKiB0aGlzLmNmZy5vdXRwdXRMZW5ndGgpIC8gMzI7XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIF9kb1Byb2Nlc3NCbG9jazogZnVuY3Rpb24gKE0sIG9mZnNldCkge1xuXHQgICAgICAgICAgICAvLyBTaG9ydGN1dHNcblx0ICAgICAgICAgICAgdmFyIHN0YXRlID0gdGhpcy5fc3RhdGU7XG5cdCAgICAgICAgICAgIHZhciBuQmxvY2tTaXplTGFuZXMgPSB0aGlzLmJsb2NrU2l6ZSAvIDI7XG5cblx0ICAgICAgICAgICAgLy8gQWJzb3JiXG5cdCAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbkJsb2NrU2l6ZUxhbmVzOyBpKyspIHtcblx0ICAgICAgICAgICAgICAgIC8vIFNob3J0Y3V0c1xuXHQgICAgICAgICAgICAgICAgdmFyIE0yaSAgPSBNW29mZnNldCArIDIgKiBpXTtcblx0ICAgICAgICAgICAgICAgIHZhciBNMmkxID0gTVtvZmZzZXQgKyAyICogaSArIDFdO1xuXG5cdCAgICAgICAgICAgICAgICAvLyBTd2FwIGVuZGlhblxuXHQgICAgICAgICAgICAgICAgTTJpID0gKFxuXHQgICAgICAgICAgICAgICAgICAgICgoKE0yaSA8PCA4KSAgfCAoTTJpID4+PiAyNCkpICYgMHgwMGZmMDBmZikgfFxuXHQgICAgICAgICAgICAgICAgICAgICgoKE0yaSA8PCAyNCkgfCAoTTJpID4+PiA4KSkgICYgMHhmZjAwZmYwMClcblx0ICAgICAgICAgICAgICAgICk7XG5cdCAgICAgICAgICAgICAgICBNMmkxID0gKFxuXHQgICAgICAgICAgICAgICAgICAgICgoKE0yaTEgPDwgOCkgIHwgKE0yaTEgPj4+IDI0KSkgJiAweDAwZmYwMGZmKSB8XG5cdCAgICAgICAgICAgICAgICAgICAgKCgoTTJpMSA8PCAyNCkgfCAoTTJpMSA+Pj4gOCkpICAmIDB4ZmYwMGZmMDApXG5cdCAgICAgICAgICAgICAgICApO1xuXG5cdCAgICAgICAgICAgICAgICAvLyBBYnNvcmIgbWVzc2FnZSBpbnRvIHN0YXRlXG5cdCAgICAgICAgICAgICAgICB2YXIgbGFuZSA9IHN0YXRlW2ldO1xuXHQgICAgICAgICAgICAgICAgbGFuZS5oaWdoIF49IE0yaTE7XG5cdCAgICAgICAgICAgICAgICBsYW5lLmxvdyAgXj0gTTJpO1xuXHQgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgLy8gUm91bmRzXG5cdCAgICAgICAgICAgIGZvciAodmFyIHJvdW5kID0gMDsgcm91bmQgPCAyNDsgcm91bmQrKykge1xuXHQgICAgICAgICAgICAgICAgLy8gVGhldGFcblx0ICAgICAgICAgICAgICAgIGZvciAodmFyIHggPSAwOyB4IDwgNTsgeCsrKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgLy8gTWl4IGNvbHVtbiBsYW5lc1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciB0TXN3ID0gMCwgdExzdyA9IDA7XG5cdCAgICAgICAgICAgICAgICAgICAgZm9yICh2YXIgeSA9IDA7IHkgPCA1OyB5KyspIHtcblx0ICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGxhbmUgPSBzdGF0ZVt4ICsgNSAqIHldO1xuXHQgICAgICAgICAgICAgICAgICAgICAgICB0TXN3IF49IGxhbmUuaGlnaDtcblx0ICAgICAgICAgICAgICAgICAgICAgICAgdExzdyBePSBsYW5lLmxvdztcblx0ICAgICAgICAgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgICAgICAgICAvLyBUZW1wb3JhcnkgdmFsdWVzXG5cdCAgICAgICAgICAgICAgICAgICAgdmFyIFR4ID0gVFt4XTtcblx0ICAgICAgICAgICAgICAgICAgICBUeC5oaWdoID0gdE1zdztcblx0ICAgICAgICAgICAgICAgICAgICBUeC5sb3cgID0gdExzdztcblx0ICAgICAgICAgICAgICAgIH1cblx0ICAgICAgICAgICAgICAgIGZvciAodmFyIHggPSAwOyB4IDwgNTsgeCsrKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgLy8gU2hvcnRjdXRzXG5cdCAgICAgICAgICAgICAgICAgICAgdmFyIFR4NCA9IFRbKHggKyA0KSAlIDVdO1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciBUeDEgPSBUWyh4ICsgMSkgJSA1XTtcblx0ICAgICAgICAgICAgICAgICAgICB2YXIgVHgxTXN3ID0gVHgxLmhpZ2g7XG5cdCAgICAgICAgICAgICAgICAgICAgdmFyIFR4MUxzdyA9IFR4MS5sb3c7XG5cblx0ICAgICAgICAgICAgICAgICAgICAvLyBNaXggc3Vycm91bmRpbmcgY29sdW1uc1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciB0TXN3ID0gVHg0LmhpZ2ggXiAoKFR4MU1zdyA8PCAxKSB8IChUeDFMc3cgPj4+IDMxKSk7XG5cdCAgICAgICAgICAgICAgICAgICAgdmFyIHRMc3cgPSBUeDQubG93ICBeICgoVHgxTHN3IDw8IDEpIHwgKFR4MU1zdyA+Pj4gMzEpKTtcblx0ICAgICAgICAgICAgICAgICAgICBmb3IgKHZhciB5ID0gMDsgeSA8IDU7IHkrKykge1xuXHQgICAgICAgICAgICAgICAgICAgICAgICB2YXIgbGFuZSA9IHN0YXRlW3ggKyA1ICogeV07XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIGxhbmUuaGlnaCBePSB0TXN3O1xuXHQgICAgICAgICAgICAgICAgICAgICAgICBsYW5lLmxvdyAgXj0gdExzdztcblx0ICAgICAgICAgICAgICAgICAgICB9XG5cdCAgICAgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgICAgIC8vIFJobyBQaVxuXHQgICAgICAgICAgICAgICAgZm9yICh2YXIgbGFuZUluZGV4ID0gMTsgbGFuZUluZGV4IDwgMjU7IGxhbmVJbmRleCsrKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgLy8gU2hvcnRjdXRzXG5cdCAgICAgICAgICAgICAgICAgICAgdmFyIGxhbmUgPSBzdGF0ZVtsYW5lSW5kZXhdO1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciBsYW5lTXN3ID0gbGFuZS5oaWdoO1xuXHQgICAgICAgICAgICAgICAgICAgIHZhciBsYW5lTHN3ID0gbGFuZS5sb3c7XG5cdCAgICAgICAgICAgICAgICAgICAgdmFyIHJob09mZnNldCA9IFJIT19PRkZTRVRTW2xhbmVJbmRleF07XG5cblx0ICAgICAgICAgICAgICAgICAgICAvLyBSb3RhdGUgbGFuZXNcblx0ICAgICAgICAgICAgICAgICAgICBpZiAocmhvT2Zmc2V0IDwgMzIpIHtcblx0ICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHRNc3cgPSAobGFuZU1zdyA8PCByaG9PZmZzZXQpIHwgKGxhbmVMc3cgPj4+ICgzMiAtIHJob09mZnNldCkpO1xuXHQgICAgICAgICAgICAgICAgICAgICAgICB2YXIgdExzdyA9IChsYW5lTHN3IDw8IHJob09mZnNldCkgfCAobGFuZU1zdyA+Pj4gKDMyIC0gcmhvT2Zmc2V0KSk7XG5cdCAgICAgICAgICAgICAgICAgICAgfSBlbHNlIC8qIGlmIChyaG9PZmZzZXQgPj0gMzIpICovIHtcblx0ICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHRNc3cgPSAobGFuZUxzdyA8PCAocmhvT2Zmc2V0IC0gMzIpKSB8IChsYW5lTXN3ID4+PiAoNjQgLSByaG9PZmZzZXQpKTtcblx0ICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHRMc3cgPSAobGFuZU1zdyA8PCAocmhvT2Zmc2V0IC0gMzIpKSB8IChsYW5lTHN3ID4+PiAoNjQgLSByaG9PZmZzZXQpKTtcblx0ICAgICAgICAgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgICAgICAgICAvLyBUcmFuc3Bvc2UgbGFuZXNcblx0ICAgICAgICAgICAgICAgICAgICB2YXIgVFBpTGFuZSA9IFRbUElfSU5ERVhFU1tsYW5lSW5kZXhdXTtcblx0ICAgICAgICAgICAgICAgICAgICBUUGlMYW5lLmhpZ2ggPSB0TXN3O1xuXHQgICAgICAgICAgICAgICAgICAgIFRQaUxhbmUubG93ICA9IHRMc3c7XG5cdCAgICAgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgICAgIC8vIFJobyBwaSBhdCB4ID0geSA9IDBcblx0ICAgICAgICAgICAgICAgIHZhciBUMCA9IFRbMF07XG5cdCAgICAgICAgICAgICAgICB2YXIgc3RhdGUwID0gc3RhdGVbMF07XG5cdCAgICAgICAgICAgICAgICBUMC5oaWdoID0gc3RhdGUwLmhpZ2g7XG5cdCAgICAgICAgICAgICAgICBUMC5sb3cgID0gc3RhdGUwLmxvdztcblxuXHQgICAgICAgICAgICAgICAgLy8gQ2hpXG5cdCAgICAgICAgICAgICAgICBmb3IgKHZhciB4ID0gMDsgeCA8IDU7IHgrKykge1xuXHQgICAgICAgICAgICAgICAgICAgIGZvciAodmFyIHkgPSAwOyB5IDwgNTsgeSsrKSB7XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNob3J0Y3V0c1xuXHQgICAgICAgICAgICAgICAgICAgICAgICB2YXIgbGFuZUluZGV4ID0geCArIDUgKiB5O1xuXHQgICAgICAgICAgICAgICAgICAgICAgICB2YXIgbGFuZSA9IHN0YXRlW2xhbmVJbmRleF07XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIHZhciBUTGFuZSA9IFRbbGFuZUluZGV4XTtcblx0ICAgICAgICAgICAgICAgICAgICAgICAgdmFyIFR4MUxhbmUgPSBUWygoeCArIDEpICUgNSkgKyA1ICogeV07XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIHZhciBUeDJMYW5lID0gVFsoKHggKyAyKSAlIDUpICsgNSAqIHldO1xuXG5cdCAgICAgICAgICAgICAgICAgICAgICAgIC8vIE1peCByb3dzXG5cdCAgICAgICAgICAgICAgICAgICAgICAgIGxhbmUuaGlnaCA9IFRMYW5lLmhpZ2ggXiAoflR4MUxhbmUuaGlnaCAmIFR4MkxhbmUuaGlnaCk7XG5cdCAgICAgICAgICAgICAgICAgICAgICAgIGxhbmUubG93ICA9IFRMYW5lLmxvdyAgXiAoflR4MUxhbmUubG93ICAmIFR4MkxhbmUubG93KTtcblx0ICAgICAgICAgICAgICAgICAgICB9XG5cdCAgICAgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgICAgIC8vIElvdGFcblx0ICAgICAgICAgICAgICAgIHZhciBsYW5lID0gc3RhdGVbMF07XG5cdCAgICAgICAgICAgICAgICB2YXIgcm91bmRDb25zdGFudCA9IFJPVU5EX0NPTlNUQU5UU1tyb3VuZF07XG5cdCAgICAgICAgICAgICAgICBsYW5lLmhpZ2ggXj0gcm91bmRDb25zdGFudC5oaWdoO1xuXHQgICAgICAgICAgICAgICAgbGFuZS5sb3cgIF49IHJvdW5kQ29uc3RhbnQubG93Oztcblx0ICAgICAgICAgICAgfVxuXHQgICAgICAgIH0sXG5cblx0ICAgICAgICBfZG9GaW5hbGl6ZTogZnVuY3Rpb24gKCkge1xuXHQgICAgICAgICAgICAvLyBTaG9ydGN1dHNcblx0ICAgICAgICAgICAgdmFyIGRhdGEgPSB0aGlzLl9kYXRhO1xuXHQgICAgICAgICAgICB2YXIgZGF0YVdvcmRzID0gZGF0YS53b3Jkcztcblx0ICAgICAgICAgICAgdmFyIG5CaXRzVG90YWwgPSB0aGlzLl9uRGF0YUJ5dGVzICogODtcblx0ICAgICAgICAgICAgdmFyIG5CaXRzTGVmdCA9IGRhdGEuc2lnQnl0ZXMgKiA4O1xuXHQgICAgICAgICAgICB2YXIgYmxvY2tTaXplQml0cyA9IHRoaXMuYmxvY2tTaXplICogMzI7XG5cblx0ICAgICAgICAgICAgLy8gQWRkIHBhZGRpbmdcblx0ICAgICAgICAgICAgZGF0YVdvcmRzW25CaXRzTGVmdCA+Pj4gNV0gfD0gMHgxIDw8ICgyNCAtIG5CaXRzTGVmdCAlIDMyKTtcblx0ICAgICAgICAgICAgZGF0YVdvcmRzWygoTWF0aC5jZWlsKChuQml0c0xlZnQgKyAxKSAvIGJsb2NrU2l6ZUJpdHMpICogYmxvY2tTaXplQml0cykgPj4+IDUpIC0gMV0gfD0gMHg4MDtcblx0ICAgICAgICAgICAgZGF0YS5zaWdCeXRlcyA9IGRhdGFXb3Jkcy5sZW5ndGggKiA0O1xuXG5cdCAgICAgICAgICAgIC8vIEhhc2ggZmluYWwgYmxvY2tzXG5cdCAgICAgICAgICAgIHRoaXMuX3Byb2Nlc3MoKTtcblxuXHQgICAgICAgICAgICAvLyBTaG9ydGN1dHNcblx0ICAgICAgICAgICAgdmFyIHN0YXRlID0gdGhpcy5fc3RhdGU7XG5cdCAgICAgICAgICAgIHZhciBvdXRwdXRMZW5ndGhCeXRlcyA9IHRoaXMuY2ZnLm91dHB1dExlbmd0aCAvIDg7XG5cdCAgICAgICAgICAgIHZhciBvdXRwdXRMZW5ndGhMYW5lcyA9IG91dHB1dExlbmd0aEJ5dGVzIC8gODtcblxuXHQgICAgICAgICAgICAvLyBTcXVlZXplXG5cdCAgICAgICAgICAgIHZhciBoYXNoV29yZHMgPSBbXTtcblx0ICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBvdXRwdXRMZW5ndGhMYW5lczsgaSsrKSB7XG5cdCAgICAgICAgICAgICAgICAvLyBTaG9ydGN1dHNcblx0ICAgICAgICAgICAgICAgIHZhciBsYW5lID0gc3RhdGVbaV07XG5cdCAgICAgICAgICAgICAgICB2YXIgbGFuZU1zdyA9IGxhbmUuaGlnaDtcblx0ICAgICAgICAgICAgICAgIHZhciBsYW5lTHN3ID0gbGFuZS5sb3c7XG5cblx0ICAgICAgICAgICAgICAgIC8vIFN3YXAgZW5kaWFuXG5cdCAgICAgICAgICAgICAgICBsYW5lTXN3ID0gKFxuXHQgICAgICAgICAgICAgICAgICAgICgoKGxhbmVNc3cgPDwgOCkgIHwgKGxhbmVNc3cgPj4+IDI0KSkgJiAweDAwZmYwMGZmKSB8XG5cdCAgICAgICAgICAgICAgICAgICAgKCgobGFuZU1zdyA8PCAyNCkgfCAobGFuZU1zdyA+Pj4gOCkpICAmIDB4ZmYwMGZmMDApXG5cdCAgICAgICAgICAgICAgICApO1xuXHQgICAgICAgICAgICAgICAgbGFuZUxzdyA9IChcblx0ICAgICAgICAgICAgICAgICAgICAoKChsYW5lTHN3IDw8IDgpICB8IChsYW5lTHN3ID4+PiAyNCkpICYgMHgwMGZmMDBmZikgfFxuXHQgICAgICAgICAgICAgICAgICAgICgoKGxhbmVMc3cgPDwgMjQpIHwgKGxhbmVMc3cgPj4+IDgpKSAgJiAweGZmMDBmZjAwKVxuXHQgICAgICAgICAgICAgICAgKTtcblxuXHQgICAgICAgICAgICAgICAgLy8gU3F1ZWV6ZSBzdGF0ZSB0byByZXRyaWV2ZSBoYXNoXG5cdCAgICAgICAgICAgICAgICBoYXNoV29yZHMucHVzaChsYW5lTHN3KTtcblx0ICAgICAgICAgICAgICAgIGhhc2hXb3Jkcy5wdXNoKGxhbmVNc3cpO1xuXHQgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgLy8gUmV0dXJuIGZpbmFsIGNvbXB1dGVkIGhhc2hcblx0ICAgICAgICAgICAgcmV0dXJuIG5ldyBXb3JkQXJyYXkuaW5pdChoYXNoV29yZHMsIG91dHB1dExlbmd0aEJ5dGVzKTtcblx0ICAgICAgICB9LFxuXG5cdCAgICAgICAgY2xvbmU6IGZ1bmN0aW9uICgpIHtcblx0ICAgICAgICAgICAgdmFyIGNsb25lID0gSGFzaGVyLmNsb25lLmNhbGwodGhpcyk7XG5cblx0ICAgICAgICAgICAgdmFyIHN0YXRlID0gY2xvbmUuX3N0YXRlID0gdGhpcy5fc3RhdGUuc2xpY2UoMCk7XG5cdCAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgMjU7IGkrKykge1xuXHQgICAgICAgICAgICAgICAgc3RhdGVbaV0gPSBzdGF0ZVtpXS5jbG9uZSgpO1xuXHQgICAgICAgICAgICB9XG5cblx0ICAgICAgICAgICAgcmV0dXJuIGNsb25lO1xuXHQgICAgICAgIH1cblx0ICAgIH0pO1xuXG5cdCAgICAvKipcblx0ICAgICAqIFNob3J0Y3V0IGZ1bmN0aW9uIHRvIHRoZSBoYXNoZXIncyBvYmplY3QgaW50ZXJmYWNlLlxuXHQgICAgICpcblx0ICAgICAqIEBwYXJhbSB7V29yZEFycmF5fHN0cmluZ30gbWVzc2FnZSBUaGUgbWVzc2FnZSB0byBoYXNoLlxuXHQgICAgICpcblx0ICAgICAqIEByZXR1cm4ge1dvcmRBcnJheX0gVGhlIGhhc2guXG5cdCAgICAgKlxuXHQgICAgICogQHN0YXRpY1xuXHQgICAgICpcblx0ICAgICAqIEBleGFtcGxlXG5cdCAgICAgKlxuXHQgICAgICogICAgIHZhciBoYXNoID0gQ3J5cHRvSlMuU0hBMygnbWVzc2FnZScpO1xuXHQgICAgICogICAgIHZhciBoYXNoID0gQ3J5cHRvSlMuU0hBMyh3b3JkQXJyYXkpO1xuXHQgICAgICovXG5cdCAgICBDLlNIQTMgPSBIYXNoZXIuX2NyZWF0ZUhlbHBlcihTSEEzKTtcblxuXHQgICAgLyoqXG5cdCAgICAgKiBTaG9ydGN1dCBmdW5jdGlvbiB0byB0aGUgSE1BQydzIG9iamVjdCBpbnRlcmZhY2UuXG5cdCAgICAgKlxuXHQgICAgICogQHBhcmFtIHtXb3JkQXJyYXl8c3RyaW5nfSBtZXNzYWdlIFRoZSBtZXNzYWdlIHRvIGhhc2guXG5cdCAgICAgKiBAcGFyYW0ge1dvcmRBcnJheXxzdHJpbmd9IGtleSBUaGUgc2VjcmV0IGtleS5cblx0ICAgICAqXG5cdCAgICAgKiBAcmV0dXJuIHtXb3JkQXJyYXl9IFRoZSBITUFDLlxuXHQgICAgICpcblx0ICAgICAqIEBzdGF0aWNcblx0ICAgICAqXG5cdCAgICAgKiBAZXhhbXBsZVxuXHQgICAgICpcblx0ICAgICAqICAgICB2YXIgaG1hYyA9IENyeXB0b0pTLkhtYWNTSEEzKG1lc3NhZ2UsIGtleSk7XG5cdCAgICAgKi9cblx0ICAgIEMuSG1hY1NIQTMgPSBIYXNoZXIuX2NyZWF0ZUhtYWNIZWxwZXIoU0hBMyk7XG5cdH0oTWF0aCkpO1xuXG5cblx0cmV0dXJuIENyeXB0b0pTLlNIQTM7XG5cbn0pKTsiLCI7KGZ1bmN0aW9uIChyb290LCBmYWN0b3J5KSB7XG5cdGlmICh0eXBlb2YgZXhwb3J0cyA9PT0gXCJvYmplY3RcIikge1xuXHRcdC8vIENvbW1vbkpTXG5cdFx0bW9kdWxlLmV4cG9ydHMgPSBleHBvcnRzID0gZmFjdG9yeShyZXF1aXJlKFwiLi9jb3JlXCIpKTtcblx0fVxuXHRlbHNlIGlmICh0eXBlb2YgZGVmaW5lID09PSBcImZ1bmN0aW9uXCIgJiYgZGVmaW5lLmFtZCkge1xuXHRcdC8vIEFNRFxuXHRcdGRlZmluZShbXCIuL2NvcmVcIl0sIGZhY3RvcnkpO1xuXHR9XG5cdGVsc2Uge1xuXHRcdC8vIEdsb2JhbCAoYnJvd3Nlcilcblx0XHRmYWN0b3J5KHJvb3QuQ3J5cHRvSlMpO1xuXHR9XG59KHRoaXMsIGZ1bmN0aW9uIChDcnlwdG9KUykge1xuXG5cdChmdW5jdGlvbiAodW5kZWZpbmVkKSB7XG5cdCAgICAvLyBTaG9ydGN1dHNcblx0ICAgIHZhciBDID0gQ3J5cHRvSlM7XG5cdCAgICB2YXIgQ19saWIgPSBDLmxpYjtcblx0ICAgIHZhciBCYXNlID0gQ19saWIuQmFzZTtcblx0ICAgIHZhciBYMzJXb3JkQXJyYXkgPSBDX2xpYi5Xb3JkQXJyYXk7XG5cblx0ICAgIC8qKlxuXHQgICAgICogeDY0IG5hbWVzcGFjZS5cblx0ICAgICAqL1xuXHQgICAgdmFyIENfeDY0ID0gQy54NjQgPSB7fTtcblxuXHQgICAgLyoqXG5cdCAgICAgKiBBIDY0LWJpdCB3b3JkLlxuXHQgICAgICovXG5cdCAgICB2YXIgWDY0V29yZCA9IENfeDY0LldvcmQgPSBCYXNlLmV4dGVuZCh7XG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogSW5pdGlhbGl6ZXMgYSBuZXdseSBjcmVhdGVkIDY0LWJpdCB3b3JkLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IGhpZ2ggVGhlIGhpZ2ggMzIgYml0cy5cblx0ICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gbG93IFRoZSBsb3cgMzIgYml0cy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIHg2NFdvcmQgPSBDcnlwdG9KUy54NjQuV29yZC5jcmVhdGUoMHgwMDAxMDIwMywgMHgwNDA1MDYwNyk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgaW5pdDogZnVuY3Rpb24gKGhpZ2gsIGxvdykge1xuXHQgICAgICAgICAgICB0aGlzLmhpZ2ggPSBoaWdoO1xuXHQgICAgICAgICAgICB0aGlzLmxvdyA9IGxvdztcblx0ICAgICAgICB9XG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBCaXR3aXNlIE5PVHMgdGhpcyB3b3JkLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7WDY0V29yZH0gQSBuZXcgeDY0LVdvcmQgb2JqZWN0IGFmdGVyIG5lZ2F0aW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgbmVnYXRlZCA9IHg2NFdvcmQubm90KCk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgLy8gbm90OiBmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgICAgIC8vIHZhciBoaWdoID0gfnRoaXMuaGlnaDtcblx0ICAgICAgICAgICAgLy8gdmFyIGxvdyA9IH50aGlzLmxvdztcblxuXHQgICAgICAgICAgICAvLyByZXR1cm4gWDY0V29yZC5jcmVhdGUoaGlnaCwgbG93KTtcblx0ICAgICAgICAvLyB9LFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogQml0d2lzZSBBTkRzIHRoaXMgd29yZCB3aXRoIHRoZSBwYXNzZWQgd29yZC5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7WDY0V29yZH0gd29yZCBUaGUgeDY0LVdvcmQgdG8gQU5EIHdpdGggdGhpcyB3b3JkLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7WDY0V29yZH0gQSBuZXcgeDY0LVdvcmQgb2JqZWN0IGFmdGVyIEFORGluZy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIGFuZGVkID0geDY0V29yZC5hbmQoYW5vdGhlclg2NFdvcmQpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIC8vIGFuZDogZnVuY3Rpb24gKHdvcmQpIHtcblx0ICAgICAgICAgICAgLy8gdmFyIGhpZ2ggPSB0aGlzLmhpZ2ggJiB3b3JkLmhpZ2g7XG5cdCAgICAgICAgICAgIC8vIHZhciBsb3cgPSB0aGlzLmxvdyAmIHdvcmQubG93O1xuXG5cdCAgICAgICAgICAgIC8vIHJldHVybiBYNjRXb3JkLmNyZWF0ZShoaWdoLCBsb3cpO1xuXHQgICAgICAgIC8vIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBCaXR3aXNlIE9ScyB0aGlzIHdvcmQgd2l0aCB0aGUgcGFzc2VkIHdvcmQuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge1g2NFdvcmR9IHdvcmQgVGhlIHg2NC1Xb3JkIHRvIE9SIHdpdGggdGhpcyB3b3JkLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7WDY0V29yZH0gQSBuZXcgeDY0LVdvcmQgb2JqZWN0IGFmdGVyIE9SaW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgb3JlZCA9IHg2NFdvcmQub3IoYW5vdGhlclg2NFdvcmQpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIC8vIG9yOiBmdW5jdGlvbiAod29yZCkge1xuXHQgICAgICAgICAgICAvLyB2YXIgaGlnaCA9IHRoaXMuaGlnaCB8IHdvcmQuaGlnaDtcblx0ICAgICAgICAgICAgLy8gdmFyIGxvdyA9IHRoaXMubG93IHwgd29yZC5sb3c7XG5cblx0ICAgICAgICAgICAgLy8gcmV0dXJuIFg2NFdvcmQuY3JlYXRlKGhpZ2gsIGxvdyk7XG5cdCAgICAgICAgLy8gfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIEJpdHdpc2UgWE9ScyB0aGlzIHdvcmQgd2l0aCB0aGUgcGFzc2VkIHdvcmQuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge1g2NFdvcmR9IHdvcmQgVGhlIHg2NC1Xb3JkIHRvIFhPUiB3aXRoIHRoaXMgd29yZC5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge1g2NFdvcmR9IEEgbmV3IHg2NC1Xb3JkIG9iamVjdCBhZnRlciBYT1JpbmcuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciB4b3JlZCA9IHg2NFdvcmQueG9yKGFub3RoZXJYNjRXb3JkKTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICAvLyB4b3I6IGZ1bmN0aW9uICh3b3JkKSB7XG5cdCAgICAgICAgICAgIC8vIHZhciBoaWdoID0gdGhpcy5oaWdoIF4gd29yZC5oaWdoO1xuXHQgICAgICAgICAgICAvLyB2YXIgbG93ID0gdGhpcy5sb3cgXiB3b3JkLmxvdztcblxuXHQgICAgICAgICAgICAvLyByZXR1cm4gWDY0V29yZC5jcmVhdGUoaGlnaCwgbG93KTtcblx0ICAgICAgICAvLyB9LFxuXG5cdCAgICAgICAgLyoqXG5cdCAgICAgICAgICogU2hpZnRzIHRoaXMgd29yZCBuIGJpdHMgdG8gdGhlIGxlZnQuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gbiBUaGUgbnVtYmVyIG9mIGJpdHMgdG8gc2hpZnQuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtYNjRXb3JkfSBBIG5ldyB4NjQtV29yZCBvYmplY3QgYWZ0ZXIgc2hpZnRpbmcuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciBzaGlmdGVkID0geDY0V29yZC5zaGlmdEwoMjUpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIC8vIHNoaWZ0TDogZnVuY3Rpb24gKG4pIHtcblx0ICAgICAgICAgICAgLy8gaWYgKG4gPCAzMikge1xuXHQgICAgICAgICAgICAgICAgLy8gdmFyIGhpZ2ggPSAodGhpcy5oaWdoIDw8IG4pIHwgKHRoaXMubG93ID4+PiAoMzIgLSBuKSk7XG5cdCAgICAgICAgICAgICAgICAvLyB2YXIgbG93ID0gdGhpcy5sb3cgPDwgbjtcblx0ICAgICAgICAgICAgLy8gfSBlbHNlIHtcblx0ICAgICAgICAgICAgICAgIC8vIHZhciBoaWdoID0gdGhpcy5sb3cgPDwgKG4gLSAzMik7XG5cdCAgICAgICAgICAgICAgICAvLyB2YXIgbG93ID0gMDtcblx0ICAgICAgICAgICAgLy8gfVxuXG5cdCAgICAgICAgICAgIC8vIHJldHVybiBYNjRXb3JkLmNyZWF0ZShoaWdoLCBsb3cpO1xuXHQgICAgICAgIC8vIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBTaGlmdHMgdGhpcyB3b3JkIG4gYml0cyB0byB0aGUgcmlnaHQuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gbiBUaGUgbnVtYmVyIG9mIGJpdHMgdG8gc2hpZnQuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcmV0dXJuIHtYNjRXb3JkfSBBIG5ldyB4NjQtV29yZCBvYmplY3QgYWZ0ZXIgc2hpZnRpbmcuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAZXhhbXBsZVxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogICAgIHZhciBzaGlmdGVkID0geDY0V29yZC5zaGlmdFIoNyk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgLy8gc2hpZnRSOiBmdW5jdGlvbiAobikge1xuXHQgICAgICAgICAgICAvLyBpZiAobiA8IDMyKSB7XG5cdCAgICAgICAgICAgICAgICAvLyB2YXIgbG93ID0gKHRoaXMubG93ID4+PiBuKSB8ICh0aGlzLmhpZ2ggPDwgKDMyIC0gbikpO1xuXHQgICAgICAgICAgICAgICAgLy8gdmFyIGhpZ2ggPSB0aGlzLmhpZ2ggPj4+IG47XG5cdCAgICAgICAgICAgIC8vIH0gZWxzZSB7XG5cdCAgICAgICAgICAgICAgICAvLyB2YXIgbG93ID0gdGhpcy5oaWdoID4+PiAobiAtIDMyKTtcblx0ICAgICAgICAgICAgICAgIC8vIHZhciBoaWdoID0gMDtcblx0ICAgICAgICAgICAgLy8gfVxuXG5cdCAgICAgICAgICAgIC8vIHJldHVybiBYNjRXb3JkLmNyZWF0ZShoaWdoLCBsb3cpO1xuXHQgICAgICAgIC8vIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBSb3RhdGVzIHRoaXMgd29yZCBuIGJpdHMgdG8gdGhlIGxlZnQuXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gbiBUaGUgbnVtYmVyIG9mIGJpdHMgdG8gcm90YXRlLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7WDY0V29yZH0gQSBuZXcgeDY0LVdvcmQgb2JqZWN0IGFmdGVyIHJvdGF0aW5nLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgcm90YXRlZCA9IHg2NFdvcmQucm90TCgyNSk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgLy8gcm90TDogZnVuY3Rpb24gKG4pIHtcblx0ICAgICAgICAgICAgLy8gcmV0dXJuIHRoaXMuc2hpZnRMKG4pLm9yKHRoaXMuc2hpZnRSKDY0IC0gbikpO1xuXHQgICAgICAgIC8vIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBSb3RhdGVzIHRoaXMgd29yZCBuIGJpdHMgdG8gdGhlIHJpZ2h0LlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHBhcmFtIHtudW1iZXJ9IG4gVGhlIG51bWJlciBvZiBiaXRzIHRvIHJvdGF0ZS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge1g2NFdvcmR9IEEgbmV3IHg2NC1Xb3JkIG9iamVjdCBhZnRlciByb3RhdGluZy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIHJvdGF0ZWQgPSB4NjRXb3JkLnJvdFIoNyk7XG5cdCAgICAgICAgICovXG5cdCAgICAgICAgLy8gcm90UjogZnVuY3Rpb24gKG4pIHtcblx0ICAgICAgICAgICAgLy8gcmV0dXJuIHRoaXMuc2hpZnRSKG4pLm9yKHRoaXMuc2hpZnRMKDY0IC0gbikpO1xuXHQgICAgICAgIC8vIH0sXG5cblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBBZGRzIHRoaXMgd29yZCB3aXRoIHRoZSBwYXNzZWQgd29yZC5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7WDY0V29yZH0gd29yZCBUaGUgeDY0LVdvcmQgdG8gYWRkIHdpdGggdGhpcyB3b3JkLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQHJldHVybiB7WDY0V29yZH0gQSBuZXcgeDY0LVdvcmQgb2JqZWN0IGFmdGVyIGFkZGluZy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIGFkZGVkID0geDY0V29yZC5hZGQoYW5vdGhlclg2NFdvcmQpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIC8vIGFkZDogZnVuY3Rpb24gKHdvcmQpIHtcblx0ICAgICAgICAgICAgLy8gdmFyIGxvdyA9ICh0aGlzLmxvdyArIHdvcmQubG93KSB8IDA7XG5cdCAgICAgICAgICAgIC8vIHZhciBjYXJyeSA9IChsb3cgPj4+IDApIDwgKHRoaXMubG93ID4+PiAwKSA/IDEgOiAwO1xuXHQgICAgICAgICAgICAvLyB2YXIgaGlnaCA9ICh0aGlzLmhpZ2ggKyB3b3JkLmhpZ2ggKyBjYXJyeSkgfCAwO1xuXG5cdCAgICAgICAgICAgIC8vIHJldHVybiBYNjRXb3JkLmNyZWF0ZShoaWdoLCBsb3cpO1xuXHQgICAgICAgIC8vIH1cblx0ICAgIH0pO1xuXG5cdCAgICAvKipcblx0ICAgICAqIEFuIGFycmF5IG9mIDY0LWJpdCB3b3Jkcy5cblx0ICAgICAqXG5cdCAgICAgKiBAcHJvcGVydHkge0FycmF5fSB3b3JkcyBUaGUgYXJyYXkgb2YgQ3J5cHRvSlMueDY0LldvcmQgb2JqZWN0cy5cblx0ICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBzaWdCeXRlcyBUaGUgbnVtYmVyIG9mIHNpZ25pZmljYW50IGJ5dGVzIGluIHRoaXMgd29yZCBhcnJheS5cblx0ICAgICAqL1xuXHQgICAgdmFyIFg2NFdvcmRBcnJheSA9IENfeDY0LldvcmRBcnJheSA9IEJhc2UuZXh0ZW5kKHtcblx0ICAgICAgICAvKipcblx0ICAgICAgICAgKiBJbml0aWFsaXplcyBhIG5ld2x5IGNyZWF0ZWQgd29yZCBhcnJheS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBwYXJhbSB7QXJyYXl9IHdvcmRzIChPcHRpb25hbCkgQW4gYXJyYXkgb2YgQ3J5cHRvSlMueDY0LldvcmQgb2JqZWN0cy5cblx0ICAgICAgICAgKiBAcGFyYW0ge251bWJlcn0gc2lnQnl0ZXMgKE9wdGlvbmFsKSBUaGUgbnVtYmVyIG9mIHNpZ25pZmljYW50IGJ5dGVzIGluIHRoZSB3b3Jkcy5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIHdvcmRBcnJheSA9IENyeXB0b0pTLng2NC5Xb3JkQXJyYXkuY3JlYXRlKCk7XG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIHdvcmRBcnJheSA9IENyeXB0b0pTLng2NC5Xb3JkQXJyYXkuY3JlYXRlKFtcblx0ICAgICAgICAgKiAgICAgICAgIENyeXB0b0pTLng2NC5Xb3JkLmNyZWF0ZSgweDAwMDEwMjAzLCAweDA0MDUwNjA3KSxcblx0ICAgICAgICAgKiAgICAgICAgIENyeXB0b0pTLng2NC5Xb3JkLmNyZWF0ZSgweDE4MTkxYTFiLCAweDFjMWQxZTFmKVxuXHQgICAgICAgICAqICAgICBdKTtcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgd29yZEFycmF5ID0gQ3J5cHRvSlMueDY0LldvcmRBcnJheS5jcmVhdGUoW1xuXHQgICAgICAgICAqICAgICAgICAgQ3J5cHRvSlMueDY0LldvcmQuY3JlYXRlKDB4MDAwMTAyMDMsIDB4MDQwNTA2MDcpLFxuXHQgICAgICAgICAqICAgICAgICAgQ3J5cHRvSlMueDY0LldvcmQuY3JlYXRlKDB4MTgxOTFhMWIsIDB4MWMxZDFlMWYpXG5cdCAgICAgICAgICogICAgIF0sIDEwKTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICBpbml0OiBmdW5jdGlvbiAod29yZHMsIHNpZ0J5dGVzKSB7XG5cdCAgICAgICAgICAgIHdvcmRzID0gdGhpcy53b3JkcyA9IHdvcmRzIHx8IFtdO1xuXG5cdCAgICAgICAgICAgIGlmIChzaWdCeXRlcyAhPSB1bmRlZmluZWQpIHtcblx0ICAgICAgICAgICAgICAgIHRoaXMuc2lnQnl0ZXMgPSBzaWdCeXRlcztcblx0ICAgICAgICAgICAgfSBlbHNlIHtcblx0ICAgICAgICAgICAgICAgIHRoaXMuc2lnQnl0ZXMgPSB3b3Jkcy5sZW5ndGggKiA4O1xuXHQgICAgICAgICAgICB9XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIENvbnZlcnRzIHRoaXMgNjQtYml0IHdvcmQgYXJyYXkgdG8gYSAzMi1iaXQgd29yZCBhcnJheS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge0NyeXB0b0pTLmxpYi5Xb3JkQXJyYXl9IFRoaXMgd29yZCBhcnJheSdzIGRhdGEgYXMgYSAzMi1iaXQgd29yZCBhcnJheS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEBleGFtcGxlXG5cdCAgICAgICAgICpcblx0ICAgICAgICAgKiAgICAgdmFyIHgzMldvcmRBcnJheSA9IHg2NFdvcmRBcnJheS50b1gzMigpO1xuXHQgICAgICAgICAqL1xuXHQgICAgICAgIHRvWDMyOiBmdW5jdGlvbiAoKSB7XG5cdCAgICAgICAgICAgIC8vIFNob3J0Y3V0c1xuXHQgICAgICAgICAgICB2YXIgeDY0V29yZHMgPSB0aGlzLndvcmRzO1xuXHQgICAgICAgICAgICB2YXIgeDY0V29yZHNMZW5ndGggPSB4NjRXb3Jkcy5sZW5ndGg7XG5cblx0ICAgICAgICAgICAgLy8gQ29udmVydFxuXHQgICAgICAgICAgICB2YXIgeDMyV29yZHMgPSBbXTtcblx0ICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB4NjRXb3Jkc0xlbmd0aDsgaSsrKSB7XG5cdCAgICAgICAgICAgICAgICB2YXIgeDY0V29yZCA9IHg2NFdvcmRzW2ldO1xuXHQgICAgICAgICAgICAgICAgeDMyV29yZHMucHVzaCh4NjRXb3JkLmhpZ2gpO1xuXHQgICAgICAgICAgICAgICAgeDMyV29yZHMucHVzaCh4NjRXb3JkLmxvdyk7XG5cdCAgICAgICAgICAgIH1cblxuXHQgICAgICAgICAgICByZXR1cm4gWDMyV29yZEFycmF5LmNyZWF0ZSh4MzJXb3JkcywgdGhpcy5zaWdCeXRlcyk7XG5cdCAgICAgICAgfSxcblxuXHQgICAgICAgIC8qKlxuXHQgICAgICAgICAqIENyZWF0ZXMgYSBjb3B5IG9mIHRoaXMgd29yZCBhcnJheS5cblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqIEByZXR1cm4ge1g2NFdvcmRBcnJheX0gVGhlIGNsb25lLlxuXHQgICAgICAgICAqXG5cdCAgICAgICAgICogQGV4YW1wbGVcblx0ICAgICAgICAgKlxuXHQgICAgICAgICAqICAgICB2YXIgY2xvbmUgPSB4NjRXb3JkQXJyYXkuY2xvbmUoKTtcblx0ICAgICAgICAgKi9cblx0ICAgICAgICBjbG9uZTogZnVuY3Rpb24gKCkge1xuXHQgICAgICAgICAgICB2YXIgY2xvbmUgPSBCYXNlLmNsb25lLmNhbGwodGhpcyk7XG5cblx0ICAgICAgICAgICAgLy8gQ2xvbmUgXCJ3b3Jkc1wiIGFycmF5XG5cdCAgICAgICAgICAgIHZhciB3b3JkcyA9IGNsb25lLndvcmRzID0gdGhpcy53b3Jkcy5zbGljZSgwKTtcblxuXHQgICAgICAgICAgICAvLyBDbG9uZSBlYWNoIFg2NFdvcmQgb2JqZWN0XG5cdCAgICAgICAgICAgIHZhciB3b3Jkc0xlbmd0aCA9IHdvcmRzLmxlbmd0aDtcblx0ICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB3b3Jkc0xlbmd0aDsgaSsrKSB7XG5cdCAgICAgICAgICAgICAgICB3b3Jkc1tpXSA9IHdvcmRzW2ldLmNsb25lKCk7XG5cdCAgICAgICAgICAgIH1cblxuXHQgICAgICAgICAgICByZXR1cm4gY2xvbmU7XG5cdCAgICAgICAgfVxuXHQgICAgfSk7XG5cdH0oKSk7XG5cblxuXHRyZXR1cm4gQ3J5cHRvSlM7XG5cbn0pKTsiLCIvKiEgYmlnbnVtYmVyLmpzIHYyLjAuNyBodHRwczovL2dpdGh1Yi5jb20vTWlrZU1jbC9iaWdudW1iZXIuanMvTElDRU5DRSAqL1xuXG47KGZ1bmN0aW9uIChnbG9iYWwpIHtcbiAgICAndXNlIHN0cmljdCc7XG5cbiAgICAvKlxuICAgICAgYmlnbnVtYmVyLmpzIHYyLjAuN1xuICAgICAgQSBKYXZhU2NyaXB0IGxpYnJhcnkgZm9yIGFyYml0cmFyeS1wcmVjaXNpb24gYXJpdGhtZXRpYy5cbiAgICAgIGh0dHBzOi8vZ2l0aHViLmNvbS9NaWtlTWNsL2JpZ251bWJlci5qc1xuICAgICAgQ29weXJpZ2h0IChjKSAyMDE1IE1pY2hhZWwgTWNsYXVnaGxpbiA8TThjaDg4bEBnbWFpbC5jb20+XG4gICAgICBNSVQgRXhwYXQgTGljZW5jZVxuICAgICovXG5cblxuICAgIHZhciBCaWdOdW1iZXIsIGNyeXB0bywgcGFyc2VOdW1lcmljLFxuICAgICAgICBpc051bWVyaWMgPSAvXi0/KFxcZCsoXFwuXFxkKik/fFxcLlxcZCspKGVbKy1dP1xcZCspPyQvaSxcbiAgICAgICAgbWF0aGNlaWwgPSBNYXRoLmNlaWwsXG4gICAgICAgIG1hdGhmbG9vciA9IE1hdGguZmxvb3IsXG4gICAgICAgIG5vdEJvb2wgPSAnIG5vdCBhIGJvb2xlYW4gb3IgYmluYXJ5IGRpZ2l0JyxcbiAgICAgICAgcm91bmRpbmdNb2RlID0gJ3JvdW5kaW5nIG1vZGUnLFxuICAgICAgICB0b29NYW55RGlnaXRzID0gJ251bWJlciB0eXBlIGhhcyBtb3JlIHRoYW4gMTUgc2lnbmlmaWNhbnQgZGlnaXRzJyxcbiAgICAgICAgQUxQSEFCRVQgPSAnMDEyMzQ1Njc4OWFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVokXycsXG4gICAgICAgIEJBU0UgPSAxZTE0LFxuICAgICAgICBMT0dfQkFTRSA9IDE0LFxuICAgICAgICBNQVhfU0FGRV9JTlRFR0VSID0gMHgxZmZmZmZmZmZmZmZmZiwgICAgICAgICAvLyAyXjUzIC0gMVxuICAgICAgICAvLyBNQVhfSU5UMzIgPSAweDdmZmZmZmZmLCAgICAgICAgICAgICAgICAgICAvLyAyXjMxIC0gMVxuICAgICAgICBQT1dTX1RFTiA9IFsxLCAxMCwgMTAwLCAxZTMsIDFlNCwgMWU1LCAxZTYsIDFlNywgMWU4LCAxZTksIDFlMTAsIDFlMTEsIDFlMTIsIDFlMTNdLFxuICAgICAgICBTUVJUX0JBU0UgPSAxZTcsXG5cbiAgICAgICAgLypcbiAgICAgICAgICogVGhlIGxpbWl0IG9uIHRoZSB2YWx1ZSBvZiBERUNJTUFMX1BMQUNFUywgVE9fRVhQX05FRywgVE9fRVhQX1BPUywgTUlOX0VYUCwgTUFYX0VYUCwgYW5kXG4gICAgICAgICAqIHRoZSBhcmd1bWVudHMgdG8gdG9FeHBvbmVudGlhbCwgdG9GaXhlZCwgdG9Gb3JtYXQsIGFuZCB0b1ByZWNpc2lvbiwgYmV5b25kIHdoaWNoIGFuXG4gICAgICAgICAqIGV4Y2VwdGlvbiBpcyB0aHJvd24gKGlmIEVSUk9SUyBpcyB0cnVlKS5cbiAgICAgICAgICovXG4gICAgICAgIE1BWCA9IDFFOTsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIDAgdG8gTUFYX0lOVDMyXG5cblxuICAgIC8qXG4gICAgICogQ3JlYXRlIGFuZCByZXR1cm4gYSBCaWdOdW1iZXIgY29uc3RydWN0b3IuXG4gICAgICovXG4gICAgZnVuY3Rpb24gYW5vdGhlcihjb25maWdPYmopIHtcbiAgICAgICAgdmFyIGRpdixcblxuICAgICAgICAgICAgLy8gaWQgdHJhY2tzIHRoZSBjYWxsZXIgZnVuY3Rpb24sIHNvIGl0cyBuYW1lIGNhbiBiZSBpbmNsdWRlZCBpbiBlcnJvciBtZXNzYWdlcy5cbiAgICAgICAgICAgIGlkID0gMCxcbiAgICAgICAgICAgIFAgPSBCaWdOdW1iZXIucHJvdG90eXBlLFxuICAgICAgICAgICAgT05FID0gbmV3IEJpZ051bWJlcigxKSxcblxuXG4gICAgICAgICAgICAvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqIEVESVRBQkxFIERFRkFVTFRTICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cblxuICAgICAgICAgICAgLypcbiAgICAgICAgICAgICAqIFRoZSBkZWZhdWx0IHZhbHVlcyBiZWxvdyBtdXN0IGJlIGludGVnZXJzIHdpdGhpbiB0aGUgaW5jbHVzaXZlIHJhbmdlcyBzdGF0ZWQuXG4gICAgICAgICAgICAgKiBUaGUgdmFsdWVzIGNhbiBhbHNvIGJlIGNoYW5nZWQgYXQgcnVuLXRpbWUgdXNpbmcgQmlnTnVtYmVyLmNvbmZpZy5cbiAgICAgICAgICAgICAqL1xuXG4gICAgICAgICAgICAvLyBUaGUgbWF4aW11bSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgZm9yIG9wZXJhdGlvbnMgaW52b2x2aW5nIGRpdmlzaW9uLlxuICAgICAgICAgICAgREVDSU1BTF9QTEFDRVMgPSAyMCwgICAgICAgICAgICAgICAgICAgICAvLyAwIHRvIE1BWFxuXG4gICAgICAgICAgICAvKlxuICAgICAgICAgICAgICogVGhlIHJvdW5kaW5nIG1vZGUgdXNlZCB3aGVuIHJvdW5kaW5nIHRvIHRoZSBhYm92ZSBkZWNpbWFsIHBsYWNlcywgYW5kIHdoZW4gdXNpbmdcbiAgICAgICAgICAgICAqIHRvRXhwb25lbnRpYWwsIHRvRml4ZWQsIHRvRm9ybWF0IGFuZCB0b1ByZWNpc2lvbiwgYW5kIHJvdW5kIChkZWZhdWx0IHZhbHVlKS5cbiAgICAgICAgICAgICAqIFVQICAgICAgICAgMCBBd2F5IGZyb20gemVyby5cbiAgICAgICAgICAgICAqIERPV04gICAgICAgMSBUb3dhcmRzIHplcm8uXG4gICAgICAgICAgICAgKiBDRUlMICAgICAgIDIgVG93YXJkcyArSW5maW5pdHkuXG4gICAgICAgICAgICAgKiBGTE9PUiAgICAgIDMgVG93YXJkcyAtSW5maW5pdHkuXG4gICAgICAgICAgICAgKiBIQUxGX1VQICAgIDQgVG93YXJkcyBuZWFyZXN0IG5laWdoYm91ci4gSWYgZXF1aWRpc3RhbnQsIHVwLlxuICAgICAgICAgICAgICogSEFMRl9ET1dOICA1IFRvd2FyZHMgbmVhcmVzdCBuZWlnaGJvdXIuIElmIGVxdWlkaXN0YW50LCBkb3duLlxuICAgICAgICAgICAgICogSEFMRl9FVkVOICA2IFRvd2FyZHMgbmVhcmVzdCBuZWlnaGJvdXIuIElmIGVxdWlkaXN0YW50LCB0b3dhcmRzIGV2ZW4gbmVpZ2hib3VyLlxuICAgICAgICAgICAgICogSEFMRl9DRUlMICA3IFRvd2FyZHMgbmVhcmVzdCBuZWlnaGJvdXIuIElmIGVxdWlkaXN0YW50LCB0b3dhcmRzICtJbmZpbml0eS5cbiAgICAgICAgICAgICAqIEhBTEZfRkxPT1IgOCBUb3dhcmRzIG5lYXJlc3QgbmVpZ2hib3VyLiBJZiBlcXVpZGlzdGFudCwgdG93YXJkcyAtSW5maW5pdHkuXG4gICAgICAgICAgICAgKi9cbiAgICAgICAgICAgIFJPVU5ESU5HX01PREUgPSA0LCAgICAgICAgICAgICAgICAgICAgICAgLy8gMCB0byA4XG5cbiAgICAgICAgICAgIC8vIEVYUE9ORU5USUFMX0FUIDogW1RPX0VYUF9ORUcgLCBUT19FWFBfUE9TXVxuXG4gICAgICAgICAgICAvLyBUaGUgZXhwb25lbnQgdmFsdWUgYXQgYW5kIGJlbmVhdGggd2hpY2ggdG9TdHJpbmcgcmV0dXJucyBleHBvbmVudGlhbCBub3RhdGlvbi5cbiAgICAgICAgICAgIC8vIE51bWJlciB0eXBlOiAtN1xuICAgICAgICAgICAgVE9fRVhQX05FRyA9IC03LCAgICAgICAgICAgICAgICAgICAgICAgICAvLyAwIHRvIC1NQVhcblxuICAgICAgICAgICAgLy8gVGhlIGV4cG9uZW50IHZhbHVlIGF0IGFuZCBhYm92ZSB3aGljaCB0b1N0cmluZyByZXR1cm5zIGV4cG9uZW50aWFsIG5vdGF0aW9uLlxuICAgICAgICAgICAgLy8gTnVtYmVyIHR5cGU6IDIxXG4gICAgICAgICAgICBUT19FWFBfUE9TID0gMjEsICAgICAgICAgICAgICAgICAgICAgICAgIC8vIDAgdG8gTUFYXG5cbiAgICAgICAgICAgIC8vIFJBTkdFIDogW01JTl9FWFAsIE1BWF9FWFBdXG5cbiAgICAgICAgICAgIC8vIFRoZSBtaW5pbXVtIGV4cG9uZW50IHZhbHVlLCBiZW5lYXRoIHdoaWNoIHVuZGVyZmxvdyB0byB6ZXJvIG9jY3Vycy5cbiAgICAgICAgICAgIC8vIE51bWJlciB0eXBlOiAtMzI0ICAoNWUtMzI0KVxuICAgICAgICAgICAgTUlOX0VYUCA9IC0xZTcsICAgICAgICAgICAgICAgICAgICAgICAgICAvLyAtMSB0byAtTUFYXG5cbiAgICAgICAgICAgIC8vIFRoZSBtYXhpbXVtIGV4cG9uZW50IHZhbHVlLCBhYm92ZSB3aGljaCBvdmVyZmxvdyB0byBJbmZpbml0eSBvY2N1cnMuXG4gICAgICAgICAgICAvLyBOdW1iZXIgdHlwZTogIDMwOCAgKDEuNzk3NjkzMTM0ODYyMzE1N2UrMzA4KVxuICAgICAgICAgICAgLy8gRm9yIE1BWF9FWFAgPiAxZTcsIGUuZy4gbmV3IEJpZ051bWJlcignMWUxMDAwMDAwMDAnKS5wbHVzKDEpIG1heSBiZSBzbG93LlxuICAgICAgICAgICAgTUFYX0VYUCA9IDFlNywgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyAxIHRvIE1BWFxuXG4gICAgICAgICAgICAvLyBXaGV0aGVyIEJpZ051bWJlciBFcnJvcnMgYXJlIGV2ZXIgdGhyb3duLlxuICAgICAgICAgICAgRVJST1JTID0gdHJ1ZSwgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0cnVlIG9yIGZhbHNlXG5cbiAgICAgICAgICAgIC8vIENoYW5nZSB0byBpbnRWYWxpZGF0b3JOb0Vycm9ycyBpZiBFUlJPUlMgaXMgZmFsc2UuXG4gICAgICAgICAgICBpc1ZhbGlkSW50ID0gaW50VmFsaWRhdG9yV2l0aEVycm9ycywgICAgIC8vIGludFZhbGlkYXRvcldpdGhFcnJvcnMvaW50VmFsaWRhdG9yTm9FcnJvcnNcblxuICAgICAgICAgICAgLy8gV2hldGhlciB0byB1c2UgY3J5cHRvZ3JhcGhpY2FsbHktc2VjdXJlIHJhbmRvbSBudW1iZXIgZ2VuZXJhdGlvbiwgaWYgYXZhaWxhYmxlLlxuICAgICAgICAgICAgQ1JZUFRPID0gZmFsc2UsICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0cnVlIG9yIGZhbHNlXG5cbiAgICAgICAgICAgIC8qXG4gICAgICAgICAgICAgKiBUaGUgbW9kdWxvIG1vZGUgdXNlZCB3aGVuIGNhbGN1bGF0aW5nIHRoZSBtb2R1bHVzOiBhIG1vZCBuLlxuICAgICAgICAgICAgICogVGhlIHF1b3RpZW50IChxID0gYSAvIG4pIGlzIGNhbGN1bGF0ZWQgYWNjb3JkaW5nIHRvIHRoZSBjb3JyZXNwb25kaW5nIHJvdW5kaW5nIG1vZGUuXG4gICAgICAgICAgICAgKiBUaGUgcmVtYWluZGVyIChyKSBpcyBjYWxjdWxhdGVkIGFzOiByID0gYSAtIG4gKiBxLlxuICAgICAgICAgICAgICpcbiAgICAgICAgICAgICAqIFVQICAgICAgICAwIFRoZSByZW1haW5kZXIgaXMgcG9zaXRpdmUgaWYgdGhlIGRpdmlkZW5kIGlzIG5lZ2F0aXZlLCBlbHNlIGlzIG5lZ2F0aXZlLlxuICAgICAgICAgICAgICogRE9XTiAgICAgIDEgVGhlIHJlbWFpbmRlciBoYXMgdGhlIHNhbWUgc2lnbiBhcyB0aGUgZGl2aWRlbmQuXG4gICAgICAgICAgICAgKiAgICAgICAgICAgICBUaGlzIG1vZHVsbyBtb2RlIGlzIGNvbW1vbmx5IGtub3duIGFzICd0cnVuY2F0ZWQgZGl2aXNpb24nIGFuZCBpc1xuICAgICAgICAgICAgICogICAgICAgICAgICAgZXF1aXZhbGVudCB0byAoYSAlIG4pIGluIEphdmFTY3JpcHQuXG4gICAgICAgICAgICAgKiBGTE9PUiAgICAgMyBUaGUgcmVtYWluZGVyIGhhcyB0aGUgc2FtZSBzaWduIGFzIHRoZSBkaXZpc29yIChQeXRob24gJSkuXG4gICAgICAgICAgICAgKiBIQUxGX0VWRU4gNiBUaGlzIG1vZHVsbyBtb2RlIGltcGxlbWVudHMgdGhlIElFRUUgNzU0IHJlbWFpbmRlciBmdW5jdGlvbi5cbiAgICAgICAgICAgICAqIEVVQ0xJRCAgICA5IEV1Y2xpZGlhbiBkaXZpc2lvbi4gcSA9IHNpZ24obikgKiBmbG9vcihhIC8gYWJzKG4pKS5cbiAgICAgICAgICAgICAqICAgICAgICAgICAgIFRoZSByZW1haW5kZXIgaXMgYWx3YXlzIHBvc2l0aXZlLlxuICAgICAgICAgICAgICpcbiAgICAgICAgICAgICAqIFRoZSB0cnVuY2F0ZWQgZGl2aXNpb24sIGZsb29yZWQgZGl2aXNpb24sIEV1Y2xpZGlhbiBkaXZpc2lvbiBhbmQgSUVFRSA3NTQgcmVtYWluZGVyXG4gICAgICAgICAgICAgKiBtb2RlcyBhcmUgY29tbW9ubHkgdXNlZCBmb3IgdGhlIG1vZHVsdXMgb3BlcmF0aW9uLlxuICAgICAgICAgICAgICogQWx0aG91Z2ggdGhlIG90aGVyIHJvdW5kaW5nIG1vZGVzIGNhbiBhbHNvIGJlIHVzZWQsIHRoZXkgbWF5IG5vdCBnaXZlIHVzZWZ1bCByZXN1bHRzLlxuICAgICAgICAgICAgICovXG4gICAgICAgICAgICBNT0RVTE9fTU9ERSA9IDEsICAgICAgICAgICAgICAgICAgICAgICAgIC8vIDAgdG8gOVxuXG4gICAgICAgICAgICAvLyBUaGUgbWF4aW11bSBudW1iZXIgb2Ygc2lnbmlmaWNhbnQgZGlnaXRzIG9mIHRoZSByZXN1bHQgb2YgdGhlIHRvUG93ZXIgb3BlcmF0aW9uLlxuICAgICAgICAgICAgLy8gSWYgUE9XX1BSRUNJU0lPTiBpcyAwLCB0aGVyZSB3aWxsIGJlIHVubGltaXRlZCBzaWduaWZpY2FudCBkaWdpdHMuXG4gICAgICAgICAgICBQT1dfUFJFQ0lTSU9OID0gMTAwLCAgICAgICAgICAgICAgICAgICAgIC8vIDAgdG8gTUFYXG5cbiAgICAgICAgICAgIC8vIFRoZSBmb3JtYXQgc3BlY2lmaWNhdGlvbiB1c2VkIGJ5IHRoZSBCaWdOdW1iZXIucHJvdG90eXBlLnRvRm9ybWF0IG1ldGhvZC5cbiAgICAgICAgICAgIEZPUk1BVCA9IHtcbiAgICAgICAgICAgICAgICBkZWNpbWFsU2VwYXJhdG9yOiAnLicsXG4gICAgICAgICAgICAgICAgZ3JvdXBTZXBhcmF0b3I6ICcsJyxcbiAgICAgICAgICAgICAgICBncm91cFNpemU6IDMsXG4gICAgICAgICAgICAgICAgc2Vjb25kYXJ5R3JvdXBTaXplOiAwLFxuICAgICAgICAgICAgICAgIGZyYWN0aW9uR3JvdXBTZXBhcmF0b3I6ICdcXHhBMCcsICAgICAgLy8gbm9uLWJyZWFraW5nIHNwYWNlXG4gICAgICAgICAgICAgICAgZnJhY3Rpb25Hcm91cFNpemU6IDBcbiAgICAgICAgICAgIH07XG5cblxuICAgICAgICAvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5cbiAgICAgICAgLy8gQ09OU1RSVUNUT1JcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFRoZSBCaWdOdW1iZXIgY29uc3RydWN0b3IgYW5kIGV4cG9ydGVkIGZ1bmN0aW9uLlxuICAgICAgICAgKiBDcmVhdGUgYW5kIHJldHVybiBhIG5ldyBpbnN0YW5jZSBvZiBhIEJpZ051bWJlciBvYmplY3QuXG4gICAgICAgICAqXG4gICAgICAgICAqIG4ge251bWJlcnxzdHJpbmd8QmlnTnVtYmVyfSBBIG51bWVyaWMgdmFsdWUuXG4gICAgICAgICAqIFtiXSB7bnVtYmVyfSBUaGUgYmFzZSBvZiBuLiBJbnRlZ2VyLCAyIHRvIDY0IGluY2x1c2l2ZS5cbiAgICAgICAgICovXG4gICAgICAgIGZ1bmN0aW9uIEJpZ051bWJlciggbiwgYiApIHtcbiAgICAgICAgICAgIHZhciBjLCBlLCBpLCBudW0sIGxlbiwgc3RyLFxuICAgICAgICAgICAgICAgIHggPSB0aGlzO1xuXG4gICAgICAgICAgICAvLyBFbmFibGUgY29uc3RydWN0b3IgdXNhZ2Ugd2l0aG91dCBuZXcuXG4gICAgICAgICAgICBpZiAoICEoIHggaW5zdGFuY2VvZiBCaWdOdW1iZXIgKSApIHtcblxuICAgICAgICAgICAgICAgIC8vICdCaWdOdW1iZXIoKSBjb25zdHJ1Y3RvciBjYWxsIHdpdGhvdXQgbmV3OiB7bn0nXG4gICAgICAgICAgICAgICAgaWYgKEVSUk9SUykgcmFpc2UoIDI2LCAnY29uc3RydWN0b3IgY2FsbCB3aXRob3V0IG5ldycsIG4gKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gbmV3IEJpZ051bWJlciggbiwgYiApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyAnbmV3IEJpZ051bWJlcigpIGJhc2Ugbm90IGFuIGludGVnZXI6IHtifSdcbiAgICAgICAgICAgIC8vICduZXcgQmlnTnVtYmVyKCkgYmFzZSBvdXQgb2YgcmFuZ2U6IHtifSdcbiAgICAgICAgICAgIGlmICggYiA9PSBudWxsIHx8ICFpc1ZhbGlkSW50KCBiLCAyLCA2NCwgaWQsICdiYXNlJyApICkge1xuXG4gICAgICAgICAgICAgICAgLy8gRHVwbGljYXRlLlxuICAgICAgICAgICAgICAgIGlmICggbiBpbnN0YW5jZW9mIEJpZ051bWJlciApIHtcbiAgICAgICAgICAgICAgICAgICAgeC5zID0gbi5zO1xuICAgICAgICAgICAgICAgICAgICB4LmUgPSBuLmU7XG4gICAgICAgICAgICAgICAgICAgIHguYyA9ICggbiA9IG4uYyApID8gbi5zbGljZSgpIDogbjtcbiAgICAgICAgICAgICAgICAgICAgaWQgPSAwO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKCAoIG51bSA9IHR5cGVvZiBuID09ICdudW1iZXInICkgJiYgbiAqIDAgPT0gMCApIHtcbiAgICAgICAgICAgICAgICAgICAgeC5zID0gMSAvIG4gPCAwID8gKCBuID0gLW4sIC0xICkgOiAxO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIEZhc3QgcGF0aCBmb3IgaW50ZWdlcnMuXG4gICAgICAgICAgICAgICAgICAgIGlmICggbiA9PT0gfn5uICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZm9yICggZSA9IDAsIGkgPSBuOyBpID49IDEwOyBpIC89IDEwLCBlKysgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHguZSA9IGU7XG4gICAgICAgICAgICAgICAgICAgICAgICB4LmMgPSBbbl07XG4gICAgICAgICAgICAgICAgICAgICAgICBpZCA9IDA7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBzdHIgPSBuICsgJyc7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCAhaXNOdW1lcmljLnRlc3QoIHN0ciA9IG4gKyAnJyApICkgcmV0dXJuIHBhcnNlTnVtZXJpYyggeCwgc3RyLCBudW0gKTtcbiAgICAgICAgICAgICAgICAgICAgeC5zID0gc3RyLmNoYXJDb2RlQXQoMCkgPT09IDQ1ID8gKCBzdHIgPSBzdHIuc2xpY2UoMSksIC0xICkgOiAxO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgYiA9IGIgfCAwO1xuICAgICAgICAgICAgICAgIHN0ciA9IG4gKyAnJztcblxuICAgICAgICAgICAgICAgIC8vIEVuc3VyZSByZXR1cm4gdmFsdWUgaXMgcm91bmRlZCB0byBERUNJTUFMX1BMQUNFUyBhcyB3aXRoIG90aGVyIGJhc2VzLlxuICAgICAgICAgICAgICAgIC8vIEFsbG93IGV4cG9uZW50aWFsIG5vdGF0aW9uIHRvIGJlIHVzZWQgd2l0aCBiYXNlIDEwIGFyZ3VtZW50LlxuICAgICAgICAgICAgICAgIGlmICggYiA9PSAxMCApIHtcbiAgICAgICAgICAgICAgICAgICAgeCA9IG5ldyBCaWdOdW1iZXIoIG4gaW5zdGFuY2VvZiBCaWdOdW1iZXIgPyBuIDogc3RyICk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiByb3VuZCggeCwgREVDSU1BTF9QTEFDRVMgKyB4LmUgKyAxLCBST1VORElOR19NT0RFICk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gQXZvaWQgcG90ZW50aWFsIGludGVycHJldGF0aW9uIG9mIEluZmluaXR5IGFuZCBOYU4gYXMgYmFzZSA0NCsgdmFsdWVzLlxuICAgICAgICAgICAgICAgIC8vIEFueSBudW1iZXIgaW4gZXhwb25lbnRpYWwgZm9ybSB3aWxsIGZhaWwgZHVlIHRvIHRoZSBbRWVdWystXS5cbiAgICAgICAgICAgICAgICBpZiAoICggbnVtID0gdHlwZW9mIG4gPT0gJ251bWJlcicgKSAmJiBuICogMCAhPSAwIHx8XG4gICAgICAgICAgICAgICAgICAhKCBuZXcgUmVnRXhwKCAnXi0/JyArICggYyA9ICdbJyArIEFMUEhBQkVULnNsaWNlKCAwLCBiICkgKyAnXSsnICkgK1xuICAgICAgICAgICAgICAgICAgICAnKD86XFxcXC4nICsgYyArICcpPyQnLGIgPCAzNyA/ICdpJyA6ICcnICkgKS50ZXN0KHN0cikgKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBwYXJzZU51bWVyaWMoIHgsIHN0ciwgbnVtLCBiICk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKG51bSkge1xuICAgICAgICAgICAgICAgICAgICB4LnMgPSAxIC8gbiA8IDAgPyAoIHN0ciA9IHN0ci5zbGljZSgxKSwgLTEgKSA6IDE7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCBFUlJPUlMgJiYgc3RyLnJlcGxhY2UoIC9eMFxcLjAqfFxcLi8sICcnICkubGVuZ3RoID4gMTUgKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICduZXcgQmlnTnVtYmVyKCkgbnVtYmVyIHR5cGUgaGFzIG1vcmUgdGhhbiAxNSBzaWduaWZpY2FudCBkaWdpdHM6IHtufSdcbiAgICAgICAgICAgICAgICAgICAgICAgIHJhaXNlKCBpZCwgdG9vTWFueURpZ2l0cywgbiApO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gUHJldmVudCBsYXRlciBjaGVjayBmb3IgbGVuZ3RoIG9uIGNvbnZlcnRlZCBudW1iZXIuXG4gICAgICAgICAgICAgICAgICAgIG51bSA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHgucyA9IHN0ci5jaGFyQ29kZUF0KDApID09PSA0NSA/ICggc3RyID0gc3RyLnNsaWNlKDEpLCAtMSApIDogMTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBzdHIgPSBjb252ZXJ0QmFzZSggc3RyLCAxMCwgYiwgeC5zICk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIERlY2ltYWwgcG9pbnQ/XG4gICAgICAgICAgICBpZiAoICggZSA9IHN0ci5pbmRleE9mKCcuJykgKSA+IC0xICkgc3RyID0gc3RyLnJlcGxhY2UoICcuJywgJycgKTtcblxuICAgICAgICAgICAgLy8gRXhwb25lbnRpYWwgZm9ybT9cbiAgICAgICAgICAgIGlmICggKCBpID0gc3RyLnNlYXJjaCggL2UvaSApICkgPiAwICkge1xuXG4gICAgICAgICAgICAgICAgLy8gRGV0ZXJtaW5lIGV4cG9uZW50LlxuICAgICAgICAgICAgICAgIGlmICggZSA8IDAgKSBlID0gaTtcbiAgICAgICAgICAgICAgICBlICs9ICtzdHIuc2xpY2UoIGkgKyAxICk7XG4gICAgICAgICAgICAgICAgc3RyID0gc3RyLnN1YnN0cmluZyggMCwgaSApO1xuICAgICAgICAgICAgfSBlbHNlIGlmICggZSA8IDAgKSB7XG5cbiAgICAgICAgICAgICAgICAvLyBJbnRlZ2VyLlxuICAgICAgICAgICAgICAgIGUgPSBzdHIubGVuZ3RoO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBEZXRlcm1pbmUgbGVhZGluZyB6ZXJvcy5cbiAgICAgICAgICAgIGZvciAoIGkgPSAwOyBzdHIuY2hhckNvZGVBdChpKSA9PT0gNDg7IGkrKyApO1xuXG4gICAgICAgICAgICAvLyBEZXRlcm1pbmUgdHJhaWxpbmcgemVyb3MuXG4gICAgICAgICAgICBmb3IgKCBsZW4gPSBzdHIubGVuZ3RoOyBzdHIuY2hhckNvZGVBdCgtLWxlbikgPT09IDQ4OyApO1xuICAgICAgICAgICAgc3RyID0gc3RyLnNsaWNlKCBpLCBsZW4gKyAxICk7XG5cbiAgICAgICAgICAgIGlmIChzdHIpIHtcbiAgICAgICAgICAgICAgICBsZW4gPSBzdHIubGVuZ3RoO1xuXG4gICAgICAgICAgICAgICAgLy8gRGlzYWxsb3cgbnVtYmVycyB3aXRoIG92ZXIgMTUgc2lnbmlmaWNhbnQgZGlnaXRzIGlmIG51bWJlciB0eXBlLlxuICAgICAgICAgICAgICAgIC8vICduZXcgQmlnTnVtYmVyKCkgbnVtYmVyIHR5cGUgaGFzIG1vcmUgdGhhbiAxNSBzaWduaWZpY2FudCBkaWdpdHM6IHtufSdcbiAgICAgICAgICAgICAgICBpZiAoIG51bSAmJiBFUlJPUlMgJiYgbGVuID4gMTUgKSByYWlzZSggaWQsIHRvb01hbnlEaWdpdHMsIHgucyAqIG4gKTtcblxuICAgICAgICAgICAgICAgIGUgPSBlIC0gaSAtIDE7XG5cbiAgICAgICAgICAgICAgICAgLy8gT3ZlcmZsb3c/XG4gICAgICAgICAgICAgICAgaWYgKCBlID4gTUFYX0VYUCApIHtcblxuICAgICAgICAgICAgICAgICAgICAvLyBJbmZpbml0eS5cbiAgICAgICAgICAgICAgICAgICAgeC5jID0geC5lID0gbnVsbDtcblxuICAgICAgICAgICAgICAgIC8vIFVuZGVyZmxvdz9cbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCBlIDwgTUlOX0VYUCApIHtcblxuICAgICAgICAgICAgICAgICAgICAvLyBaZXJvLlxuICAgICAgICAgICAgICAgICAgICB4LmMgPSBbIHguZSA9IDAgXTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB4LmUgPSBlO1xuICAgICAgICAgICAgICAgICAgICB4LmMgPSBbXTtcblxuICAgICAgICAgICAgICAgICAgICAvLyBUcmFuc2Zvcm0gYmFzZVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIGUgaXMgdGhlIGJhc2UgMTAgZXhwb25lbnQuXG4gICAgICAgICAgICAgICAgICAgIC8vIGkgaXMgd2hlcmUgdG8gc2xpY2Ugc3RyIHRvIGdldCB0aGUgZmlyc3QgZWxlbWVudCBvZiB0aGUgY29lZmZpY2llbnQgYXJyYXkuXG4gICAgICAgICAgICAgICAgICAgIGkgPSAoIGUgKyAxICkgJSBMT0dfQkFTRTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCBlIDwgMCApIGkgKz0gTE9HX0JBU0U7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCBpIDwgbGVuICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGkpIHguYy5wdXNoKCArc3RyLnNsaWNlKCAwLCBpICkgKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgZm9yICggbGVuIC09IExPR19CQVNFOyBpIDwgbGVuOyApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB4LmMucHVzaCggK3N0ci5zbGljZSggaSwgaSArPSBMT0dfQkFTRSApICk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHN0ciA9IHN0ci5zbGljZShpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGkgPSBMT0dfQkFTRSAtIHN0ci5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpIC09IGxlbjtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGZvciAoIDsgaS0tOyBzdHIgKz0gJzAnICk7XG4gICAgICAgICAgICAgICAgICAgIHguYy5wdXNoKCArc3RyICk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcblxuICAgICAgICAgICAgICAgIC8vIFplcm8uXG4gICAgICAgICAgICAgICAgeC5jID0gWyB4LmUgPSAwIF07XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlkID0gMDtcbiAgICAgICAgfVxuXG5cbiAgICAgICAgLy8gQ09OU1RSVUNUT1IgUFJPUEVSVElFU1xuXG5cbiAgICAgICAgQmlnTnVtYmVyLmFub3RoZXIgPSBhbm90aGVyO1xuXG4gICAgICAgIEJpZ051bWJlci5ST1VORF9VUCA9IDA7XG4gICAgICAgIEJpZ051bWJlci5ST1VORF9ET1dOID0gMTtcbiAgICAgICAgQmlnTnVtYmVyLlJPVU5EX0NFSUwgPSAyO1xuICAgICAgICBCaWdOdW1iZXIuUk9VTkRfRkxPT1IgPSAzO1xuICAgICAgICBCaWdOdW1iZXIuUk9VTkRfSEFMRl9VUCA9IDQ7XG4gICAgICAgIEJpZ051bWJlci5ST1VORF9IQUxGX0RPV04gPSA1O1xuICAgICAgICBCaWdOdW1iZXIuUk9VTkRfSEFMRl9FVkVOID0gNjtcbiAgICAgICAgQmlnTnVtYmVyLlJPVU5EX0hBTEZfQ0VJTCA9IDc7XG4gICAgICAgIEJpZ051bWJlci5ST1VORF9IQUxGX0ZMT09SID0gODtcbiAgICAgICAgQmlnTnVtYmVyLkVVQ0xJRCA9IDk7XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBDb25maWd1cmUgaW5mcmVxdWVudGx5LWNoYW5naW5nIGxpYnJhcnktd2lkZSBzZXR0aW5ncy5cbiAgICAgICAgICpcbiAgICAgICAgICogQWNjZXB0IGFuIG9iamVjdCBvciBhbiBhcmd1bWVudCBsaXN0LCB3aXRoIG9uZSBvciBtYW55IG9mIHRoZSBmb2xsb3dpbmcgcHJvcGVydGllcyBvclxuICAgICAgICAgKiBwYXJhbWV0ZXJzIHJlc3BlY3RpdmVseTpcbiAgICAgICAgICpcbiAgICAgICAgICogICBERUNJTUFMX1BMQUNFUyAge251bWJlcn0gIEludGVnZXIsIDAgdG8gTUFYIGluY2x1c2l2ZVxuICAgICAgICAgKiAgIFJPVU5ESU5HX01PREUgICB7bnVtYmVyfSAgSW50ZWdlciwgMCB0byA4IGluY2x1c2l2ZVxuICAgICAgICAgKiAgIEVYUE9ORU5USUFMX0FUICB7bnVtYmVyfG51bWJlcltdfSAgSW50ZWdlciwgLU1BWCB0byBNQVggaW5jbHVzaXZlIG9yXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbaW50ZWdlciAtTUFYIHRvIDAgaW5jbC4sIDAgdG8gTUFYIGluY2wuXVxuICAgICAgICAgKiAgIFJBTkdFICAgICAgICAgICB7bnVtYmVyfG51bWJlcltdfSAgTm9uLXplcm8gaW50ZWdlciwgLU1BWCB0byBNQVggaW5jbHVzaXZlIG9yXG4gICAgICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbaW50ZWdlciAtTUFYIHRvIC0xIGluY2wuLCBpbnRlZ2VyIDEgdG8gTUFYIGluY2wuXVxuICAgICAgICAgKiAgIEVSUk9SUyAgICAgICAgICB7Ym9vbGVhbnxudW1iZXJ9ICAgdHJ1ZSwgZmFsc2UsIDEgb3IgMFxuICAgICAgICAgKiAgIENSWVBUTyAgICAgICAgICB7Ym9vbGVhbnxudW1iZXJ9ICAgdHJ1ZSwgZmFsc2UsIDEgb3IgMFxuICAgICAgICAgKiAgIE1PRFVMT19NT0RFICAgICB7bnVtYmVyfSAgICAgICAgICAgMCB0byA5IGluY2x1c2l2ZVxuICAgICAgICAgKiAgIFBPV19QUkVDSVNJT04gICB7bnVtYmVyfSAgICAgICAgICAgMCB0byBNQVggaW5jbHVzaXZlXG4gICAgICAgICAqICAgRk9STUFUICAgICAgICAgIHtvYmplY3R9ICAgICAgICAgICBTZWUgQmlnTnVtYmVyLnByb3RvdHlwZS50b0Zvcm1hdFxuICAgICAgICAgKiAgICAgIGRlY2ltYWxTZXBhcmF0b3IgICAgICAge3N0cmluZ31cbiAgICAgICAgICogICAgICBncm91cFNlcGFyYXRvciAgICAgICAgIHtzdHJpbmd9XG4gICAgICAgICAqICAgICAgZ3JvdXBTaXplICAgICAgICAgICAgICB7bnVtYmVyfVxuICAgICAgICAgKiAgICAgIHNlY29uZGFyeUdyb3VwU2l6ZSAgICAge251bWJlcn1cbiAgICAgICAgICogICAgICBmcmFjdGlvbkdyb3VwU2VwYXJhdG9yIHtzdHJpbmd9XG4gICAgICAgICAqICAgICAgZnJhY3Rpb25Hcm91cFNpemUgICAgICB7bnVtYmVyfVxuICAgICAgICAgKlxuICAgICAgICAgKiAoVGhlIHZhbHVlcyBhc3NpZ25lZCB0byB0aGUgYWJvdmUgRk9STUFUIG9iamVjdCBwcm9wZXJ0aWVzIGFyZSBub3QgY2hlY2tlZCBmb3IgdmFsaWRpdHkuKVxuICAgICAgICAgKlxuICAgICAgICAgKiBFLmcuXG4gICAgICAgICAqIEJpZ051bWJlci5jb25maWcoMjAsIDQpIGlzIGVxdWl2YWxlbnQgdG9cbiAgICAgICAgICogQmlnTnVtYmVyLmNvbmZpZyh7IERFQ0lNQUxfUExBQ0VTIDogMjAsIFJPVU5ESU5HX01PREUgOiA0IH0pXG4gICAgICAgICAqXG4gICAgICAgICAqIElnbm9yZSBwcm9wZXJ0aWVzL3BhcmFtZXRlcnMgc2V0IHRvIG51bGwgb3IgdW5kZWZpbmVkLlxuICAgICAgICAgKiBSZXR1cm4gYW4gb2JqZWN0IHdpdGggdGhlIHByb3BlcnRpZXMgY3VycmVudCB2YWx1ZXMuXG4gICAgICAgICAqL1xuICAgICAgICBCaWdOdW1iZXIuY29uZmlnID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHYsIHAsXG4gICAgICAgICAgICAgICAgaSA9IDAsXG4gICAgICAgICAgICAgICAgciA9IHt9LFxuICAgICAgICAgICAgICAgIGEgPSBhcmd1bWVudHMsXG4gICAgICAgICAgICAgICAgbyA9IGFbMF0sXG4gICAgICAgICAgICAgICAgaGFzID0gbyAmJiB0eXBlb2YgbyA9PSAnb2JqZWN0J1xuICAgICAgICAgICAgICAgICAgPyBmdW5jdGlvbiAoKSB7IGlmICggby5oYXNPd25Qcm9wZXJ0eShwKSApIHJldHVybiAoIHYgPSBvW3BdICkgIT0gbnVsbDsgfVxuICAgICAgICAgICAgICAgICAgOiBmdW5jdGlvbiAoKSB7IGlmICggYS5sZW5ndGggPiBpICkgcmV0dXJuICggdiA9IGFbaSsrXSApICE9IG51bGw7IH07XG5cbiAgICAgICAgICAgIC8vIERFQ0lNQUxfUExBQ0VTIHtudW1iZXJ9IEludGVnZXIsIDAgdG8gTUFYIGluY2x1c2l2ZS5cbiAgICAgICAgICAgIC8vICdjb25maWcoKSBERUNJTUFMX1BMQUNFUyBub3QgYW4gaW50ZWdlcjoge3Z9J1xuICAgICAgICAgICAgLy8gJ2NvbmZpZygpIERFQ0lNQUxfUExBQ0VTIG91dCBvZiByYW5nZToge3Z9J1xuICAgICAgICAgICAgaWYgKCBoYXMoIHAgPSAnREVDSU1BTF9QTEFDRVMnICkgJiYgaXNWYWxpZEludCggdiwgMCwgTUFYLCAyLCBwICkgKSB7XG4gICAgICAgICAgICAgICAgREVDSU1BTF9QTEFDRVMgPSB2IHwgMDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJbcF0gPSBERUNJTUFMX1BMQUNFUztcblxuICAgICAgICAgICAgLy8gUk9VTkRJTkdfTU9ERSB7bnVtYmVyfSBJbnRlZ2VyLCAwIHRvIDggaW5jbHVzaXZlLlxuICAgICAgICAgICAgLy8gJ2NvbmZpZygpIFJPVU5ESU5HX01PREUgbm90IGFuIGludGVnZXI6IHt2fSdcbiAgICAgICAgICAgIC8vICdjb25maWcoKSBST1VORElOR19NT0RFIG91dCBvZiByYW5nZToge3Z9J1xuICAgICAgICAgICAgaWYgKCBoYXMoIHAgPSAnUk9VTkRJTkdfTU9ERScgKSAmJiBpc1ZhbGlkSW50KCB2LCAwLCA4LCAyLCBwICkgKSB7XG4gICAgICAgICAgICAgICAgUk9VTkRJTkdfTU9ERSA9IHYgfCAwO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcltwXSA9IFJPVU5ESU5HX01PREU7XG5cbiAgICAgICAgICAgIC8vIEVYUE9ORU5USUFMX0FUIHtudW1iZXJ8bnVtYmVyW119XG4gICAgICAgICAgICAvLyBJbnRlZ2VyLCAtTUFYIHRvIE1BWCBpbmNsdXNpdmUgb3IgW2ludGVnZXIgLU1BWCB0byAwIGluY2x1c2l2ZSwgMCB0byBNQVggaW5jbHVzaXZlXS5cbiAgICAgICAgICAgIC8vICdjb25maWcoKSBFWFBPTkVOVElBTF9BVCBub3QgYW4gaW50ZWdlcjoge3Z9J1xuICAgICAgICAgICAgLy8gJ2NvbmZpZygpIEVYUE9ORU5USUFMX0FUIG91dCBvZiByYW5nZToge3Z9J1xuICAgICAgICAgICAgaWYgKCBoYXMoIHAgPSAnRVhQT05FTlRJQUxfQVQnICkgKSB7XG5cbiAgICAgICAgICAgICAgICBpZiAoIGlzQXJyYXkodikgKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICggaXNWYWxpZEludCggdlswXSwgLU1BWCwgMCwgMiwgcCApICYmIGlzVmFsaWRJbnQoIHZbMV0sIDAsIE1BWCwgMiwgcCApICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgVE9fRVhQX05FRyA9IHZbMF0gfCAwO1xuICAgICAgICAgICAgICAgICAgICAgICAgVE9fRVhQX1BPUyA9IHZbMV0gfCAwO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmICggaXNWYWxpZEludCggdiwgLU1BWCwgTUFYLCAyLCBwICkgKSB7XG4gICAgICAgICAgICAgICAgICAgIFRPX0VYUF9ORUcgPSAtKCBUT19FWFBfUE9TID0gKCB2IDwgMCA/IC12IDogdiApIHwgMCApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJbcF0gPSBbIFRPX0VYUF9ORUcsIFRPX0VYUF9QT1MgXTtcblxuICAgICAgICAgICAgLy8gUkFOR0Uge251bWJlcnxudW1iZXJbXX0gTm9uLXplcm8gaW50ZWdlciwgLU1BWCB0byBNQVggaW5jbHVzaXZlIG9yXG4gICAgICAgICAgICAvLyBbaW50ZWdlciAtTUFYIHRvIC0xIGluY2x1c2l2ZSwgaW50ZWdlciAxIHRvIE1BWCBpbmNsdXNpdmVdLlxuICAgICAgICAgICAgLy8gJ2NvbmZpZygpIFJBTkdFIG5vdCBhbiBpbnRlZ2VyOiB7dn0nXG4gICAgICAgICAgICAvLyAnY29uZmlnKCkgUkFOR0UgY2Fubm90IGJlIHplcm86IHt2fSdcbiAgICAgICAgICAgIC8vICdjb25maWcoKSBSQU5HRSBvdXQgb2YgcmFuZ2U6IHt2fSdcbiAgICAgICAgICAgIGlmICggaGFzKCBwID0gJ1JBTkdFJyApICkge1xuXG4gICAgICAgICAgICAgICAgaWYgKCBpc0FycmF5KHYpICkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIGlzVmFsaWRJbnQoIHZbMF0sIC1NQVgsIC0xLCAyLCBwICkgJiYgaXNWYWxpZEludCggdlsxXSwgMSwgTUFYLCAyLCBwICkgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBNSU5fRVhQID0gdlswXSB8IDA7XG4gICAgICAgICAgICAgICAgICAgICAgICBNQVhfRVhQID0gdlsxXSB8IDA7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCBpc1ZhbGlkSW50KCB2LCAtTUFYLCBNQVgsIDIsIHAgKSApIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCB2IHwgMCApIE1JTl9FWFAgPSAtKCBNQVhfRVhQID0gKCB2IDwgMCA/IC12IDogdiApIHwgMCApO1xuICAgICAgICAgICAgICAgICAgICBlbHNlIGlmIChFUlJPUlMpIHJhaXNlKCAyLCBwICsgJyBjYW5ub3QgYmUgemVybycsIHYgKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByW3BdID0gWyBNSU5fRVhQLCBNQVhfRVhQIF07XG5cbiAgICAgICAgICAgIC8vIEVSUk9SUyB7Ym9vbGVhbnxudW1iZXJ9IHRydWUsIGZhbHNlLCAxIG9yIDAuXG4gICAgICAgICAgICAvLyAnY29uZmlnKCkgRVJST1JTIG5vdCBhIGJvb2xlYW4gb3IgYmluYXJ5IGRpZ2l0OiB7dn0nXG4gICAgICAgICAgICBpZiAoIGhhcyggcCA9ICdFUlJPUlMnICkgKSB7XG5cbiAgICAgICAgICAgICAgICBpZiAoIHYgPT09ICEhdiB8fCB2ID09PSAxIHx8IHYgPT09IDAgKSB7XG4gICAgICAgICAgICAgICAgICAgIGlkID0gMDtcbiAgICAgICAgICAgICAgICAgICAgaXNWYWxpZEludCA9ICggRVJST1JTID0gISF2ICkgPyBpbnRWYWxpZGF0b3JXaXRoRXJyb3JzIDogaW50VmFsaWRhdG9yTm9FcnJvcnM7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChFUlJPUlMpIHtcbiAgICAgICAgICAgICAgICAgICAgcmFpc2UoIDIsIHAgKyBub3RCb29sLCB2ICk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcltwXSA9IEVSUk9SUztcblxuICAgICAgICAgICAgLy8gQ1JZUFRPIHtib29sZWFufG51bWJlcn0gdHJ1ZSwgZmFsc2UsIDEgb3IgMC5cbiAgICAgICAgICAgIC8vICdjb25maWcoKSBDUllQVE8gbm90IGEgYm9vbGVhbiBvciBiaW5hcnkgZGlnaXQ6IHt2fSdcbiAgICAgICAgICAgIC8vICdjb25maWcoKSBjcnlwdG8gdW5hdmFpbGFibGU6IHtjcnlwdG99J1xuICAgICAgICAgICAgaWYgKCBoYXMoIHAgPSAnQ1JZUFRPJyApICkge1xuXG4gICAgICAgICAgICAgICAgaWYgKCB2ID09PSAhIXYgfHwgdiA9PT0gMSB8fCB2ID09PSAwICkge1xuICAgICAgICAgICAgICAgICAgICBDUllQVE8gPSAhISggdiAmJiBjcnlwdG8gJiYgdHlwZW9mIGNyeXB0byA9PSAnb2JqZWN0JyApO1xuICAgICAgICAgICAgICAgICAgICBpZiAoIHYgJiYgIUNSWVBUTyAmJiBFUlJPUlMgKSByYWlzZSggMiwgJ2NyeXB0byB1bmF2YWlsYWJsZScsIGNyeXB0byApO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoRVJST1JTKSB7XG4gICAgICAgICAgICAgICAgICAgIHJhaXNlKCAyLCBwICsgbm90Qm9vbCwgdiApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJbcF0gPSBDUllQVE87XG5cbiAgICAgICAgICAgIC8vIE1PRFVMT19NT0RFIHtudW1iZXJ9IEludGVnZXIsIDAgdG8gOSBpbmNsdXNpdmUuXG4gICAgICAgICAgICAvLyAnY29uZmlnKCkgTU9EVUxPX01PREUgbm90IGFuIGludGVnZXI6IHt2fSdcbiAgICAgICAgICAgIC8vICdjb25maWcoKSBNT0RVTE9fTU9ERSBvdXQgb2YgcmFuZ2U6IHt2fSdcbiAgICAgICAgICAgIGlmICggaGFzKCBwID0gJ01PRFVMT19NT0RFJyApICYmIGlzVmFsaWRJbnQoIHYsIDAsIDksIDIsIHAgKSApIHtcbiAgICAgICAgICAgICAgICBNT0RVTE9fTU9ERSA9IHYgfCAwO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcltwXSA9IE1PRFVMT19NT0RFO1xuXG4gICAgICAgICAgICAvLyBQT1dfUFJFQ0lTSU9OIHtudW1iZXJ9IEludGVnZXIsIDAgdG8gTUFYIGluY2x1c2l2ZS5cbiAgICAgICAgICAgIC8vICdjb25maWcoKSBQT1dfUFJFQ0lTSU9OIG5vdCBhbiBpbnRlZ2VyOiB7dn0nXG4gICAgICAgICAgICAvLyAnY29uZmlnKCkgUE9XX1BSRUNJU0lPTiBvdXQgb2YgcmFuZ2U6IHt2fSdcbiAgICAgICAgICAgIGlmICggaGFzKCBwID0gJ1BPV19QUkVDSVNJT04nICkgJiYgaXNWYWxpZEludCggdiwgMCwgTUFYLCAyLCBwICkgKSB7XG4gICAgICAgICAgICAgICAgUE9XX1BSRUNJU0lPTiA9IHYgfCAwO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcltwXSA9IFBPV19QUkVDSVNJT047XG5cbiAgICAgICAgICAgIC8vIEZPUk1BVCB7b2JqZWN0fVxuICAgICAgICAgICAgLy8gJ2NvbmZpZygpIEZPUk1BVCBub3QgYW4gb2JqZWN0OiB7dn0nXG4gICAgICAgICAgICBpZiAoIGhhcyggcCA9ICdGT1JNQVQnICkgKSB7XG5cbiAgICAgICAgICAgICAgICBpZiAoIHR5cGVvZiB2ID09ICdvYmplY3QnICkge1xuICAgICAgICAgICAgICAgICAgICBGT1JNQVQgPSB2O1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoRVJST1JTKSB7XG4gICAgICAgICAgICAgICAgICAgIHJhaXNlKCAyLCBwICsgJyBub3QgYW4gb2JqZWN0JywgdiApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJbcF0gPSBGT1JNQVQ7XG5cbiAgICAgICAgICAgIHJldHVybiByO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIGEgbmV3IEJpZ051bWJlciB3aG9zZSB2YWx1ZSBpcyB0aGUgbWF4aW11bSBvZiB0aGUgYXJndW1lbnRzLlxuICAgICAgICAgKlxuICAgICAgICAgKiBhcmd1bWVudHMge251bWJlcnxzdHJpbmd8QmlnTnVtYmVyfVxuICAgICAgICAgKi9cbiAgICAgICAgQmlnTnVtYmVyLm1heCA9IGZ1bmN0aW9uICgpIHsgcmV0dXJuIG1heE9yTWluKCBhcmd1bWVudHMsIFAubHQgKTsgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiBhIG5ldyBCaWdOdW1iZXIgd2hvc2UgdmFsdWUgaXMgdGhlIG1pbmltdW0gb2YgdGhlIGFyZ3VtZW50cy5cbiAgICAgICAgICpcbiAgICAgICAgICogYXJndW1lbnRzIHtudW1iZXJ8c3RyaW5nfEJpZ051bWJlcn1cbiAgICAgICAgICovXG4gICAgICAgIEJpZ051bWJlci5taW4gPSBmdW5jdGlvbiAoKSB7IHJldHVybiBtYXhPck1pbiggYXJndW1lbnRzLCBQLmd0ICk7IH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gYSBuZXcgQmlnTnVtYmVyIHdpdGggYSByYW5kb20gdmFsdWUgZXF1YWwgdG8gb3IgZ3JlYXRlciB0aGFuIDAgYW5kIGxlc3MgdGhhbiAxLFxuICAgICAgICAgKiBhbmQgd2l0aCBkcCwgb3IgREVDSU1BTF9QTEFDRVMgaWYgZHAgaXMgb21pdHRlZCwgZGVjaW1hbCBwbGFjZXMgKG9yIGxlc3MgaWYgdHJhaWxpbmdcbiAgICAgICAgICogemVyb3MgYXJlIHByb2R1Y2VkKS5cbiAgICAgICAgICpcbiAgICAgICAgICogW2RwXSB7bnVtYmVyfSBEZWNpbWFsIHBsYWNlcy4gSW50ZWdlciwgMCB0byBNQVggaW5jbHVzaXZlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAncmFuZG9tKCkgZGVjaW1hbCBwbGFjZXMgbm90IGFuIGludGVnZXI6IHtkcH0nXG4gICAgICAgICAqICdyYW5kb20oKSBkZWNpbWFsIHBsYWNlcyBvdXQgb2YgcmFuZ2U6IHtkcH0nXG4gICAgICAgICAqICdyYW5kb20oKSBjcnlwdG8gdW5hdmFpbGFibGU6IHtjcnlwdG99J1xuICAgICAgICAgKi9cbiAgICAgICAgQmlnTnVtYmVyLnJhbmRvbSA9IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgcG93Ml81MyA9IDB4MjAwMDAwMDAwMDAwMDA7XG5cbiAgICAgICAgICAgIC8vIFJldHVybiBhIDUzIGJpdCBpbnRlZ2VyIG4sIHdoZXJlIDAgPD0gbiA8IDkwMDcxOTkyNTQ3NDA5OTIuXG4gICAgICAgICAgICAvLyBDaGVjayBpZiBNYXRoLnJhbmRvbSgpIHByb2R1Y2VzIG1vcmUgdGhhbiAzMiBiaXRzIG9mIHJhbmRvbW5lc3MuXG4gICAgICAgICAgICAvLyBJZiBpdCBkb2VzLCBhc3N1bWUgYXQgbGVhc3QgNTMgYml0cyBhcmUgcHJvZHVjZWQsIG90aGVyd2lzZSBhc3N1bWUgYXQgbGVhc3QgMzAgYml0cy5cbiAgICAgICAgICAgIC8vIDB4NDAwMDAwMDAgaXMgMl4zMCwgMHg4MDAwMDAgaXMgMl4yMywgMHgxZmZmZmYgaXMgMl4yMSAtIDEuXG4gICAgICAgICAgICB2YXIgcmFuZG9tNTNiaXRJbnQgPSAoTWF0aC5yYW5kb20oKSAqIHBvdzJfNTMpICYgMHgxZmZmZmZcbiAgICAgICAgICAgICAgPyBmdW5jdGlvbiAoKSB7IHJldHVybiBtYXRoZmxvb3IoIE1hdGgucmFuZG9tKCkgKiBwb3cyXzUzICk7IH1cbiAgICAgICAgICAgICAgOiBmdW5jdGlvbiAoKSB7IHJldHVybiAoKE1hdGgucmFuZG9tKCkgKiAweDQwMDAwMDAwIHwgMCkgKiAweDgwMDAwMCkgK1xuICAgICAgICAgICAgICAgICAgKE1hdGgucmFuZG9tKCkgKiAweDgwMDAwMCB8IDApOyB9O1xuXG4gICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24gKGRwKSB7XG4gICAgICAgICAgICAgICAgdmFyIGEsIGIsIGUsIGssIHYsXG4gICAgICAgICAgICAgICAgICAgIGkgPSAwLFxuICAgICAgICAgICAgICAgICAgICBjID0gW10sXG4gICAgICAgICAgICAgICAgICAgIHJhbmQgPSBuZXcgQmlnTnVtYmVyKE9ORSk7XG5cbiAgICAgICAgICAgICAgICBkcCA9IGRwID09IG51bGwgfHwgIWlzVmFsaWRJbnQoIGRwLCAwLCBNQVgsIDE0ICkgPyBERUNJTUFMX1BMQUNFUyA6IGRwIHwgMDtcbiAgICAgICAgICAgICAgICBrID0gbWF0aGNlaWwoIGRwIC8gTE9HX0JBU0UgKTtcblxuICAgICAgICAgICAgICAgIGlmIChDUllQVE8pIHtcblxuICAgICAgICAgICAgICAgICAgICAvLyBCcm93c2VycyBzdXBwb3J0aW5nIGNyeXB0by5nZXRSYW5kb21WYWx1ZXMuXG4gICAgICAgICAgICAgICAgICAgIGlmICggY3J5cHRvICYmIGNyeXB0by5nZXRSYW5kb21WYWx1ZXMgKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGEgPSBjcnlwdG8uZ2V0UmFuZG9tVmFsdWVzKCBuZXcgVWludDMyQXJyYXkoIGsgKj0gMiApICk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoIDsgaSA8IGs7ICkge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gNTMgYml0czpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyAoKE1hdGgucG93KDIsIDMyKSAtIDEpICogTWF0aC5wb3coMiwgMjEpKS50b1N0cmluZygyKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIDExMTExIDExMTExMTExIDExMTExMTExIDExMTExMTExIDExMTAwMDAwIDAwMDAwMDAwIDAwMDAwMDAwXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gKChNYXRoLnBvdygyLCAzMikgLSAxKSA+Pj4gMTEpLnRvU3RyaW5nKDIpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMTExMTEgMTExMTExMTEgMTExMTExMTFcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyAweDIwMDAwIGlzIDJeMjEuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdiA9IGFbaV0gKiAweDIwMDAwICsgKGFbaSArIDFdID4+PiAxMSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBSZWplY3Rpb24gc2FtcGxpbmc6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gMCA8PSB2IDwgOTAwNzE5OTI1NDc0MDk5MlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFByb2JhYmlsaXR5IHRoYXQgdiA+PSA5ZTE1LCBpc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIDcxOTkyNTQ3NDA5OTIgLyA5MDA3MTk5MjU0NzQwOTkyIH49IDAuMDAwOCwgaS5lLiAxIGluIDEyNTFcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIHYgPj0gOWUxNSApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYiA9IGNyeXB0by5nZXRSYW5kb21WYWx1ZXMoIG5ldyBVaW50MzJBcnJheSgyKSApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhW2ldID0gYlswXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYVtpICsgMV0gPSBiWzFdO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gMCA8PSB2IDw9IDg5OTk5OTk5OTk5OTk5OTlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gMCA8PSAodiAlIDFlMTQpIDw9IDk5OTk5OTk5OTk5OTk5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMucHVzaCggdiAlIDFlMTQgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaSArPSAyO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGkgPSBrIC8gMjtcblxuICAgICAgICAgICAgICAgICAgICAvLyBOb2RlLmpzIHN1cHBvcnRpbmcgY3J5cHRvLnJhbmRvbUJ5dGVzLlxuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCBjcnlwdG8gJiYgY3J5cHRvLnJhbmRvbUJ5dGVzICkge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBidWZmZXJcbiAgICAgICAgICAgICAgICAgICAgICAgIGEgPSBjcnlwdG8ucmFuZG9tQnl0ZXMoIGsgKj0gNyApO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBmb3IgKCA7IGkgPCBrOyApIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIDB4MTAwMDAwMDAwMDAwMCBpcyAyXjQ4LCAweDEwMDAwMDAwMDAwIGlzIDJeNDBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyAweDEwMDAwMDAwMCBpcyAyXjMyLCAweDEwMDAwMDAgaXMgMl4yNFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIDExMTExIDExMTExMTExIDExMTExMTExIDExMTExMTExIDExMTExMTExIDExMTExMTExIDExMTExMTExXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gMCA8PSB2IDwgOTAwNzE5OTI1NDc0MDk5MlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHYgPSAoICggYVtpXSAmIDMxICkgKiAweDEwMDAwMDAwMDAwMDAgKSArICggYVtpICsgMV0gKiAweDEwMDAwMDAwMDAwICkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICggYVtpICsgMl0gKiAweDEwMDAwMDAwMCApICsgKCBhW2kgKyAzXSAqIDB4MTAwMDAwMCApICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoIGFbaSArIDRdIDw8IDE2ICkgKyAoIGFbaSArIDVdIDw8IDggKSArIGFbaSArIDZdO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCB2ID49IDllMTUgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNyeXB0by5yYW5kb21CeXRlcyg3KS5jb3B5KCBhLCBpICk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyAwIDw9ICh2ICUgMWUxNCkgPD0gOTk5OTk5OTk5OTk5OTlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYy5wdXNoKCB2ICUgMWUxNCApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpICs9IDc7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgaSA9IGsgLyA3O1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKEVSUk9SUykge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmFpc2UoIDE0LCAnY3J5cHRvIHVuYXZhaWxhYmxlJywgY3J5cHRvICk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBVc2UgTWF0aC5yYW5kb206IENSWVBUTyBpcyBmYWxzZSBvciBjcnlwdG8gaXMgdW5hdmFpbGFibGUgYW5kIEVSUk9SUyBpcyBmYWxzZS5cbiAgICAgICAgICAgICAgICBpZiAoIWkpIHtcblxuICAgICAgICAgICAgICAgICAgICBmb3IgKCA7IGkgPCBrOyApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHYgPSByYW5kb201M2JpdEludCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCB2IDwgOWUxNSApIGNbaSsrXSA9IHYgJSAxZTE0O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgayA9IGNbLS1pXTtcbiAgICAgICAgICAgICAgICBkcCAlPSBMT0dfQkFTRTtcblxuICAgICAgICAgICAgICAgIC8vIENvbnZlcnQgdHJhaWxpbmcgZGlnaXRzIHRvIHplcm9zIGFjY29yZGluZyB0byBkcC5cbiAgICAgICAgICAgICAgICBpZiAoIGsgJiYgZHAgKSB7XG4gICAgICAgICAgICAgICAgICAgIHYgPSBQT1dTX1RFTltMT0dfQkFTRSAtIGRwXTtcbiAgICAgICAgICAgICAgICAgICAgY1tpXSA9IG1hdGhmbG9vciggayAvIHYgKSAqIHY7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gUmVtb3ZlIHRyYWlsaW5nIGVsZW1lbnRzIHdoaWNoIGFyZSB6ZXJvLlxuICAgICAgICAgICAgICAgIGZvciAoIDsgY1tpXSA9PT0gMDsgYy5wb3AoKSwgaS0tICk7XG5cbiAgICAgICAgICAgICAgICAvLyBaZXJvP1xuICAgICAgICAgICAgICAgIGlmICggaSA8IDAgKSB7XG4gICAgICAgICAgICAgICAgICAgIGMgPSBbIGUgPSAwIF07XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcblxuICAgICAgICAgICAgICAgICAgICAvLyBSZW1vdmUgbGVhZGluZyBlbGVtZW50cyB3aGljaCBhcmUgemVybyBhbmQgYWRqdXN0IGV4cG9uZW50IGFjY29yZGluZ2x5LlxuICAgICAgICAgICAgICAgICAgICBmb3IgKCBlID0gLTEgOyBjWzBdID09PSAwOyBjLnNoaWZ0KCksIGUgLT0gTE9HX0JBU0UpO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIENvdW50IHRoZSBkaWdpdHMgb2YgdGhlIGZpcnN0IGVsZW1lbnQgb2YgYyB0byBkZXRlcm1pbmUgbGVhZGluZyB6ZXJvcywgYW5kLi4uXG4gICAgICAgICAgICAgICAgICAgIGZvciAoIGkgPSAxLCB2ID0gY1swXTsgdiA+PSAxMDsgdiAvPSAxMCwgaSsrKTtcblxuICAgICAgICAgICAgICAgICAgICAvLyBhZGp1c3QgdGhlIGV4cG9uZW50IGFjY29yZGluZ2x5LlxuICAgICAgICAgICAgICAgICAgICBpZiAoIGkgPCBMT0dfQkFTRSApIGUgLT0gTE9HX0JBU0UgLSBpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJhbmQuZSA9IGU7XG4gICAgICAgICAgICAgICAgcmFuZC5jID0gYztcbiAgICAgICAgICAgICAgICByZXR1cm4gcmFuZDtcbiAgICAgICAgICAgIH07XG4gICAgICAgIH0pKCk7XG5cblxuICAgICAgICAvLyBQUklWQVRFIEZVTkNUSU9OU1xuXG5cbiAgICAgICAgLy8gQ29udmVydCBhIG51bWVyaWMgc3RyaW5nIG9mIGJhc2VJbiB0byBhIG51bWVyaWMgc3RyaW5nIG9mIGJhc2VPdXQuXG4gICAgICAgIGZ1bmN0aW9uIGNvbnZlcnRCYXNlKCBzdHIsIGJhc2VPdXQsIGJhc2VJbiwgc2lnbiApIHtcbiAgICAgICAgICAgIHZhciBkLCBlLCBrLCByLCB4LCB4YywgeSxcbiAgICAgICAgICAgICAgICBpID0gc3RyLmluZGV4T2YoICcuJyApLFxuICAgICAgICAgICAgICAgIGRwID0gREVDSU1BTF9QTEFDRVMsXG4gICAgICAgICAgICAgICAgcm0gPSBST1VORElOR19NT0RFO1xuXG4gICAgICAgICAgICBpZiAoIGJhc2VJbiA8IDM3ICkgc3RyID0gc3RyLnRvTG93ZXJDYXNlKCk7XG5cbiAgICAgICAgICAgIC8vIE5vbi1pbnRlZ2VyLlxuICAgICAgICAgICAgaWYgKCBpID49IDAgKSB7XG4gICAgICAgICAgICAgICAgayA9IFBPV19QUkVDSVNJT047XG5cbiAgICAgICAgICAgICAgICAvLyBVbmxpbWl0ZWQgcHJlY2lzaW9uLlxuICAgICAgICAgICAgICAgIFBPV19QUkVDSVNJT04gPSAwO1xuICAgICAgICAgICAgICAgIHN0ciA9IHN0ci5yZXBsYWNlKCAnLicsICcnICk7XG4gICAgICAgICAgICAgICAgeSA9IG5ldyBCaWdOdW1iZXIoYmFzZUluKTtcbiAgICAgICAgICAgICAgICB4ID0geS5wb3coIHN0ci5sZW5ndGggLSBpICk7XG4gICAgICAgICAgICAgICAgUE9XX1BSRUNJU0lPTiA9IGs7XG5cbiAgICAgICAgICAgICAgICAvLyBDb252ZXJ0IHN0ciBhcyBpZiBhbiBpbnRlZ2VyLCB0aGVuIHJlc3RvcmUgdGhlIGZyYWN0aW9uIHBhcnQgYnkgZGl2aWRpbmcgdGhlXG4gICAgICAgICAgICAgICAgLy8gcmVzdWx0IGJ5IGl0cyBiYXNlIHJhaXNlZCB0byBhIHBvd2VyLlxuICAgICAgICAgICAgICAgIHkuYyA9IHRvQmFzZU91dCggdG9GaXhlZFBvaW50KCBjb2VmZlRvU3RyaW5nKCB4LmMgKSwgeC5lICksIDEwLCBiYXNlT3V0ICk7XG4gICAgICAgICAgICAgICAgeS5lID0geS5jLmxlbmd0aDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gQ29udmVydCB0aGUgbnVtYmVyIGFzIGludGVnZXIuXG4gICAgICAgICAgICB4YyA9IHRvQmFzZU91dCggc3RyLCBiYXNlSW4sIGJhc2VPdXQgKTtcbiAgICAgICAgICAgIGUgPSBrID0geGMubGVuZ3RoO1xuXG4gICAgICAgICAgICAvLyBSZW1vdmUgdHJhaWxpbmcgemVyb3MuXG4gICAgICAgICAgICBmb3IgKCA7IHhjWy0ta10gPT0gMDsgeGMucG9wKCkgKTtcbiAgICAgICAgICAgIGlmICggIXhjWzBdICkgcmV0dXJuICcwJztcblxuICAgICAgICAgICAgaWYgKCBpIDwgMCApIHtcbiAgICAgICAgICAgICAgICAtLWU7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHguYyA9IHhjO1xuICAgICAgICAgICAgICAgIHguZSA9IGU7XG5cbiAgICAgICAgICAgICAgICAvLyBzaWduIGlzIG5lZWRlZCBmb3IgY29ycmVjdCByb3VuZGluZy5cbiAgICAgICAgICAgICAgICB4LnMgPSBzaWduO1xuICAgICAgICAgICAgICAgIHggPSBkaXYoIHgsIHksIGRwLCBybSwgYmFzZU91dCApO1xuICAgICAgICAgICAgICAgIHhjID0geC5jO1xuICAgICAgICAgICAgICAgIHIgPSB4LnI7XG4gICAgICAgICAgICAgICAgZSA9IHguZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZCA9IGUgKyBkcCArIDE7XG5cbiAgICAgICAgICAgIC8vIFRoZSByb3VuZGluZyBkaWdpdCwgaS5lLiB0aGUgZGlnaXQgdG8gdGhlIHJpZ2h0IG9mIHRoZSBkaWdpdCB0aGF0IG1heSBiZSByb3VuZGVkIHVwLlxuICAgICAgICAgICAgaSA9IHhjW2RdO1xuICAgICAgICAgICAgayA9IGJhc2VPdXQgLyAyO1xuICAgICAgICAgICAgciA9IHIgfHwgZCA8IDAgfHwgeGNbZCArIDFdICE9IG51bGw7XG5cbiAgICAgICAgICAgIHIgPSBybSA8IDQgPyAoIGkgIT0gbnVsbCB8fCByICkgJiYgKCBybSA9PSAwIHx8IHJtID09ICggeC5zIDwgMCA/IDMgOiAyICkgKVxuICAgICAgICAgICAgICAgICAgICAgICA6IGkgPiBrIHx8IGkgPT0gayAmJiggcm0gPT0gNCB8fCByIHx8IHJtID09IDYgJiYgeGNbZCAtIDFdICYgMSB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgIHJtID09ICggeC5zIDwgMCA/IDggOiA3ICkgKTtcblxuICAgICAgICAgICAgaWYgKCBkIDwgMSB8fCAheGNbMF0gKSB7XG5cbiAgICAgICAgICAgICAgICAvLyAxXi1kcCBvciAwLlxuICAgICAgICAgICAgICAgIHN0ciA9IHIgPyB0b0ZpeGVkUG9pbnQoICcxJywgLWRwICkgOiAnMCc7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHhjLmxlbmd0aCA9IGQ7XG5cbiAgICAgICAgICAgICAgICBpZiAocikge1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIFJvdW5kaW5nIHVwIG1heSBtZWFuIHRoZSBwcmV2aW91cyBkaWdpdCBoYXMgdG8gYmUgcm91bmRlZCB1cCBhbmQgc28gb24uXG4gICAgICAgICAgICAgICAgICAgIGZvciAoIC0tYmFzZU91dDsgKyt4Y1stLWRdID4gYmFzZU91dDsgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB4Y1tkXSA9IDA7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICggIWQgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKytlO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhjLnVuc2hpZnQoMSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBEZXRlcm1pbmUgdHJhaWxpbmcgemVyb3MuXG4gICAgICAgICAgICAgICAgZm9yICggayA9IHhjLmxlbmd0aDsgIXhjWy0ta107ICk7XG5cbiAgICAgICAgICAgICAgICAvLyBFLmcuIFs0LCAxMSwgMTVdIGJlY29tZXMgNGJmLlxuICAgICAgICAgICAgICAgIGZvciAoIGkgPSAwLCBzdHIgPSAnJzsgaSA8PSBrOyBzdHIgKz0gQUxQSEFCRVQuY2hhckF0KCB4Y1tpKytdICkgKTtcbiAgICAgICAgICAgICAgICBzdHIgPSB0b0ZpeGVkUG9pbnQoIHN0ciwgZSApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBUaGUgY2FsbGVyIHdpbGwgYWRkIHRoZSBzaWduLlxuICAgICAgICAgICAgcmV0dXJuIHN0cjtcbiAgICAgICAgfVxuXG5cbiAgICAgICAgLy8gUGVyZm9ybSBkaXZpc2lvbiBpbiB0aGUgc3BlY2lmaWVkIGJhc2UuIENhbGxlZCBieSBkaXYgYW5kIGNvbnZlcnRCYXNlLlxuICAgICAgICBkaXYgPSAoZnVuY3Rpb24gKCkge1xuXG4gICAgICAgICAgICAvLyBBc3N1bWUgbm9uLXplcm8geCBhbmQgay5cbiAgICAgICAgICAgIGZ1bmN0aW9uIG11bHRpcGx5KCB4LCBrLCBiYXNlICkge1xuICAgICAgICAgICAgICAgIHZhciBtLCB0ZW1wLCB4bG8sIHhoaSxcbiAgICAgICAgICAgICAgICAgICAgY2FycnkgPSAwLFxuICAgICAgICAgICAgICAgICAgICBpID0geC5sZW5ndGgsXG4gICAgICAgICAgICAgICAgICAgIGtsbyA9IGsgJSBTUVJUX0JBU0UsXG4gICAgICAgICAgICAgICAgICAgIGtoaSA9IGsgLyBTUVJUX0JBU0UgfCAwO1xuXG4gICAgICAgICAgICAgICAgZm9yICggeCA9IHguc2xpY2UoKTsgaS0tOyApIHtcbiAgICAgICAgICAgICAgICAgICAgeGxvID0geFtpXSAlIFNRUlRfQkFTRTtcbiAgICAgICAgICAgICAgICAgICAgeGhpID0geFtpXSAvIFNRUlRfQkFTRSB8IDA7XG4gICAgICAgICAgICAgICAgICAgIG0gPSBraGkgKiB4bG8gKyB4aGkgKiBrbG87XG4gICAgICAgICAgICAgICAgICAgIHRlbXAgPSBrbG8gKiB4bG8gKyAoICggbSAlIFNRUlRfQkFTRSApICogU1FSVF9CQVNFICkgKyBjYXJyeTtcbiAgICAgICAgICAgICAgICAgICAgY2FycnkgPSAoIHRlbXAgLyBiYXNlIHwgMCApICsgKCBtIC8gU1FSVF9CQVNFIHwgMCApICsga2hpICogeGhpO1xuICAgICAgICAgICAgICAgICAgICB4W2ldID0gdGVtcCAlIGJhc2U7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKGNhcnJ5KSB4LnVuc2hpZnQoY2FycnkpO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHg7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGZ1bmN0aW9uIGNvbXBhcmUoIGEsIGIsIGFMLCBiTCApIHtcbiAgICAgICAgICAgICAgICB2YXIgaSwgY21wO1xuXG4gICAgICAgICAgICAgICAgaWYgKCBhTCAhPSBiTCApIHtcbiAgICAgICAgICAgICAgICAgICAgY21wID0gYUwgPiBiTCA/IDEgOiAtMTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuXG4gICAgICAgICAgICAgICAgICAgIGZvciAoIGkgPSBjbXAgPSAwOyBpIDwgYUw7IGkrKyApIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCBhW2ldICE9IGJbaV0gKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY21wID0gYVtpXSA+IGJbaV0gPyAxIDogLTE7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIGNtcDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZnVuY3Rpb24gc3VidHJhY3QoIGEsIGIsIGFMLCBiYXNlICkge1xuICAgICAgICAgICAgICAgIHZhciBpID0gMDtcblxuICAgICAgICAgICAgICAgIC8vIFN1YnRyYWN0IGIgZnJvbSBhLlxuICAgICAgICAgICAgICAgIGZvciAoIDsgYUwtLTsgKSB7XG4gICAgICAgICAgICAgICAgICAgIGFbYUxdIC09IGk7XG4gICAgICAgICAgICAgICAgICAgIGkgPSBhW2FMXSA8IGJbYUxdID8gMSA6IDA7XG4gICAgICAgICAgICAgICAgICAgIGFbYUxdID0gaSAqIGJhc2UgKyBhW2FMXSAtIGJbYUxdO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIFJlbW92ZSBsZWFkaW5nIHplcm9zLlxuICAgICAgICAgICAgICAgIGZvciAoIDsgIWFbMF0gJiYgYS5sZW5ndGggPiAxOyBhLnNoaWZ0KCkgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8geDogZGl2aWRlbmQsIHk6IGRpdmlzb3IuXG4gICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24gKCB4LCB5LCBkcCwgcm0sIGJhc2UgKSB7XG4gICAgICAgICAgICAgICAgdmFyIGNtcCwgZSwgaSwgbW9yZSwgbiwgcHJvZCwgcHJvZEwsIHEsIHFjLCByZW0sIHJlbUwsIHJlbTAsIHhpLCB4TCwgeWMwLFxuICAgICAgICAgICAgICAgICAgICB5TCwgeXosXG4gICAgICAgICAgICAgICAgICAgIHMgPSB4LnMgPT0geS5zID8gMSA6IC0xLFxuICAgICAgICAgICAgICAgICAgICB4YyA9IHguYyxcbiAgICAgICAgICAgICAgICAgICAgeWMgPSB5LmM7XG5cbiAgICAgICAgICAgICAgICAvLyBFaXRoZXIgTmFOLCBJbmZpbml0eSBvciAwP1xuICAgICAgICAgICAgICAgIGlmICggIXhjIHx8ICF4Y1swXSB8fCAheWMgfHwgIXljWzBdICkge1xuXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBuZXcgQmlnTnVtYmVyKFxuXG4gICAgICAgICAgICAgICAgICAgICAgLy8gUmV0dXJuIE5hTiBpZiBlaXRoZXIgTmFOLCBvciBib3RoIEluZmluaXR5IG9yIDAuXG4gICAgICAgICAgICAgICAgICAgICAgIXgucyB8fCAheS5zIHx8ICggeGMgPyB5YyAmJiB4Y1swXSA9PSB5Y1swXSA6ICF5YyApID8gTmFOIDpcblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gUmV0dXJuIMKxMCBpZiB4IGlzIMKxMCBvciB5IGlzIMKxSW5maW5pdHksIG9yIHJldHVybiDCsUluZmluaXR5IGFzIHkgaXMgwrEwLlxuICAgICAgICAgICAgICAgICAgICAgICAgeGMgJiYgeGNbMF0gPT0gMCB8fCAheWMgPyBzICogMCA6IHMgLyAwXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcSA9IG5ldyBCaWdOdW1iZXIocyk7XG4gICAgICAgICAgICAgICAgcWMgPSBxLmMgPSBbXTtcbiAgICAgICAgICAgICAgICBlID0geC5lIC0geS5lO1xuICAgICAgICAgICAgICAgIHMgPSBkcCArIGUgKyAxO1xuXG4gICAgICAgICAgICAgICAgaWYgKCAhYmFzZSApIHtcbiAgICAgICAgICAgICAgICAgICAgYmFzZSA9IEJBU0U7XG4gICAgICAgICAgICAgICAgICAgIGUgPSBiaXRGbG9vciggeC5lIC8gTE9HX0JBU0UgKSAtIGJpdEZsb29yKCB5LmUgLyBMT0dfQkFTRSApO1xuICAgICAgICAgICAgICAgICAgICBzID0gcyAvIExPR19CQVNFIHwgMDtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBSZXN1bHQgZXhwb25lbnQgbWF5IGJlIG9uZSBsZXNzIHRoZW4gdGhlIGN1cnJlbnQgdmFsdWUgb2YgZS5cbiAgICAgICAgICAgICAgICAvLyBUaGUgY29lZmZpY2llbnRzIG9mIHRoZSBCaWdOdW1iZXJzIGZyb20gY29udmVydEJhc2UgbWF5IGhhdmUgdHJhaWxpbmcgemVyb3MuXG4gICAgICAgICAgICAgICAgZm9yICggaSA9IDA7IHljW2ldID09ICggeGNbaV0gfHwgMCApOyBpKysgKTtcbiAgICAgICAgICAgICAgICBpZiAoIHljW2ldID4gKCB4Y1tpXSB8fCAwICkgKSBlLS07XG5cbiAgICAgICAgICAgICAgICBpZiAoIHMgPCAwICkge1xuICAgICAgICAgICAgICAgICAgICBxYy5wdXNoKDEpO1xuICAgICAgICAgICAgICAgICAgICBtb3JlID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB4TCA9IHhjLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgeUwgPSB5Yy5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgIGkgPSAwO1xuICAgICAgICAgICAgICAgICAgICBzICs9IDI7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gTm9ybWFsaXNlIHhjIGFuZCB5YyBzbyBoaWdoZXN0IG9yZGVyIGRpZ2l0IG9mIHljIGlzID49IGJhc2UgLyAyLlxuXG4gICAgICAgICAgICAgICAgICAgIG4gPSBtYXRoZmxvb3IoIGJhc2UgLyAoIHljWzBdICsgMSApICk7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gTm90IG5lY2Vzc2FyeSwgYnV0IHRvIGhhbmRsZSBvZGQgYmFzZXMgd2hlcmUgeWNbMF0gPT0gKCBiYXNlIC8gMiApIC0gMS5cbiAgICAgICAgICAgICAgICAgICAgLy8gaWYgKCBuID4gMSB8fCBuKysgPT0gMSAmJiB5Y1swXSA8IGJhc2UgLyAyICkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIG4gPiAxICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgeWMgPSBtdWx0aXBseSggeWMsIG4sIGJhc2UgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHhjID0gbXVsdGlwbHkoIHhjLCBuLCBiYXNlICk7XG4gICAgICAgICAgICAgICAgICAgICAgICB5TCA9IHljLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgICAgIHhMID0geGMubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgeGkgPSB5TDtcbiAgICAgICAgICAgICAgICAgICAgcmVtID0geGMuc2xpY2UoIDAsIHlMICk7XG4gICAgICAgICAgICAgICAgICAgIHJlbUwgPSByZW0ubGVuZ3RoO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIEFkZCB6ZXJvcyB0byBtYWtlIHJlbWFpbmRlciBhcyBsb25nIGFzIGRpdmlzb3IuXG4gICAgICAgICAgICAgICAgICAgIGZvciAoIDsgcmVtTCA8IHlMOyByZW1bcmVtTCsrXSA9IDAgKTtcbiAgICAgICAgICAgICAgICAgICAgeXogPSB5Yy5zbGljZSgpO1xuICAgICAgICAgICAgICAgICAgICB5ei51bnNoaWZ0KDApO1xuICAgICAgICAgICAgICAgICAgICB5YzAgPSB5Y1swXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCB5Y1sxXSA+PSBiYXNlIC8gMiApIHljMCsrO1xuICAgICAgICAgICAgICAgICAgICAvLyBOb3QgbmVjZXNzYXJ5LCBidXQgdG8gcHJldmVudCB0cmlhbCBkaWdpdCBuID4gYmFzZSwgd2hlbiB1c2luZyBiYXNlIDMuXG4gICAgICAgICAgICAgICAgICAgIC8vIGVsc2UgaWYgKCBiYXNlID09IDMgJiYgeWMwID09IDEgKSB5YzAgPSAxICsgMWUtMTU7XG5cbiAgICAgICAgICAgICAgICAgICAgZG8ge1xuICAgICAgICAgICAgICAgICAgICAgICAgbiA9IDA7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIENvbXBhcmUgZGl2aXNvciBhbmQgcmVtYWluZGVyLlxuICAgICAgICAgICAgICAgICAgICAgICAgY21wID0gY29tcGFyZSggeWMsIHJlbSwgeUwsIHJlbUwgKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gSWYgZGl2aXNvciA8IHJlbWFpbmRlci5cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICggY21wIDwgMCApIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIENhbGN1bGF0ZSB0cmlhbCBkaWdpdCwgbi5cblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbTAgPSByZW1bMF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCB5TCAhPSByZW1MICkgcmVtMCA9IHJlbTAgKiBiYXNlICsgKCByZW1bMV0gfHwgMCApO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gbiBpcyBob3cgbWFueSB0aW1lcyB0aGUgZGl2aXNvciBnb2VzIGludG8gdGhlIGN1cnJlbnQgcmVtYWluZGVyLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4gPSBtYXRoZmxvb3IoIHJlbTAgLyB5YzAgKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vICBBbGdvcml0aG06XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gIDEuIHByb2R1Y3QgPSBkaXZpc29yICogdHJpYWwgZGlnaXQgKG4pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gIDIuIGlmIHByb2R1Y3QgPiByZW1haW5kZXI6IHByb2R1Y3QgLT0gZGl2aXNvciwgbi0tXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gIDMuIHJlbWFpbmRlciAtPSBwcm9kdWN0XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gIDQuIGlmIHByb2R1Y3Qgd2FzIDwgcmVtYWluZGVyIGF0IDI6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgNS4gY29tcGFyZSBuZXcgcmVtYWluZGVyIGFuZCBkaXZpc29yXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgNi4gSWYgcmVtYWluZGVyID4gZGl2aXNvcjogcmVtYWluZGVyIC09IGRpdmlzb3IsIG4rK1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCBuID4gMSApIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBuIG1heSBiZSA+IGJhc2Ugb25seSB3aGVuIGJhc2UgaXMgMy5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG4gPj0gYmFzZSkgbiA9IGJhc2UgLSAxO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHByb2R1Y3QgPSBkaXZpc29yICogdHJpYWwgZGlnaXQuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2QgPSBtdWx0aXBseSggeWMsIG4sIGJhc2UgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZEwgPSBwcm9kLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVtTCA9IHJlbS5sZW5ndGg7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ29tcGFyZSBwcm9kdWN0IGFuZCByZW1haW5kZXIuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIHByb2R1Y3QgPiByZW1haW5kZXIuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFRyaWFsIGRpZ2l0IG4gdG9vIGhpZ2guXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG4gaXMgMSB0b28gaGlnaCBhYm91dCA1JSBvZiB0aGUgdGltZSwgYW5kIGlzIG5vdCBrbm93biB0byBoYXZlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGV2ZXIgYmVlbiBtb3JlIHRoYW4gMSB0b28gaGlnaC5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpbGUgKCBjb21wYXJlKCBwcm9kLCByZW0sIHByb2RMLCByZW1MICkgPT0gMSApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4tLTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU3VidHJhY3QgZGl2aXNvciBmcm9tIHByb2R1Y3QuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJ0cmFjdCggcHJvZCwgeUwgPCBwcm9kTCA/IHl6IDogeWMsIHByb2RMLCBiYXNlICk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kTCA9IHByb2QubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY21wID0gMTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gbiBpcyAwIG9yIDEsIGNtcCBpcyAtMS5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSWYgbiBpcyAwLCB0aGVyZSBpcyBubyBuZWVkIHRvIGNvbXBhcmUgeWMgYW5kIHJlbSBhZ2FpbiBiZWxvdyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gc28gY2hhbmdlIGNtcCB0byAxIHRvIGF2b2lkIGl0LlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJZiBuIGlzIDEsIGxlYXZlIGNtcCBhcyAtMSwgc28geWMgYW5kIHJlbSBhcmUgY29tcGFyZWQgYWdhaW4uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICggbiA9PSAwICkge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBkaXZpc29yIDwgcmVtYWluZGVyLCBzbyBuIG11c3QgYmUgYXQgbGVhc3QgMS5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNtcCA9IG4gPSAxO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcHJvZHVjdCA9IGRpdmlzb3JcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZCA9IHljLnNsaWNlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2RMID0gcHJvZC5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCBwcm9kTCA8IHJlbUwgKSBwcm9kLnVuc2hpZnQoMCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTdWJ0cmFjdCBwcm9kdWN0IGZyb20gcmVtYWluZGVyLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnRyYWN0KCByZW0sIHByb2QsIHJlbUwsIGJhc2UgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZW1MID0gcmVtLmxlbmd0aDtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJZiBwcm9kdWN0IHdhcyA8IHJlbWFpbmRlci5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIGNtcCA9PSAtMSApIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBDb21wYXJlIGRpdmlzb3IgYW5kIG5ldyByZW1haW5kZXIuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIGRpdmlzb3IgPCBuZXcgcmVtYWluZGVyLCBzdWJ0cmFjdCBkaXZpc29yIGZyb20gcmVtYWluZGVyLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBUcmlhbCBkaWdpdCBuIHRvbyBsb3cuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG4gaXMgMSB0b28gbG93IGFib3V0IDUlIG9mIHRoZSB0aW1lLCBhbmQgdmVyeSByYXJlbHkgMiB0b28gbG93LlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGlsZSAoIGNvbXBhcmUoIHljLCByZW0sIHlMLCByZW1MICkgPCAxICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbisrO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBTdWJ0cmFjdCBkaXZpc29yIGZyb20gcmVtYWluZGVyLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VidHJhY3QoIHJlbSwgeUwgPCByZW1MID8geXogOiB5YywgcmVtTCwgYmFzZSApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVtTCA9IHJlbS5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCBjbXAgPT09IDAgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbisrO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbSA9IFswXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gLy8gZWxzZSBjbXAgPT09IDEgYW5kIG4gd2lsbCBiZSAwXG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFkZCB0aGUgbmV4dCBkaWdpdCwgbiwgdG8gdGhlIHJlc3VsdCBhcnJheS5cbiAgICAgICAgICAgICAgICAgICAgICAgIHFjW2krK10gPSBuO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVcGRhdGUgdGhlIHJlbWFpbmRlci5cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICggcmVtWzBdICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbVtyZW1MKytdID0geGNbeGldIHx8IDA7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbSA9IFsgeGNbeGldIF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVtTCA9IDE7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0gd2hpbGUgKCAoIHhpKysgPCB4TCB8fCByZW1bMF0gIT0gbnVsbCApICYmIHMtLSApO1xuXG4gICAgICAgICAgICAgICAgICAgIG1vcmUgPSByZW1bMF0gIT0gbnVsbDtcblxuICAgICAgICAgICAgICAgICAgICAvLyBMZWFkaW5nIHplcm8/XG4gICAgICAgICAgICAgICAgICAgIGlmICggIXFjWzBdICkgcWMuc2hpZnQoKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoIGJhc2UgPT0gQkFTRSApIHtcblxuICAgICAgICAgICAgICAgICAgICAvLyBUbyBjYWxjdWxhdGUgcS5lLCBmaXJzdCBnZXQgdGhlIG51bWJlciBvZiBkaWdpdHMgb2YgcWNbMF0uXG4gICAgICAgICAgICAgICAgICAgIGZvciAoIGkgPSAxLCBzID0gcWNbMF07IHMgPj0gMTA7IHMgLz0gMTAsIGkrKyApO1xuICAgICAgICAgICAgICAgICAgICByb3VuZCggcSwgZHAgKyAoIHEuZSA9IGkgKyBlICogTE9HX0JBU0UgLSAxICkgKyAxLCBybSwgbW9yZSApO1xuXG4gICAgICAgICAgICAgICAgLy8gQ2FsbGVyIGlzIGNvbnZlcnRCYXNlLlxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHEuZSA9IGU7XG4gICAgICAgICAgICAgICAgICAgIHEuciA9ICttb3JlO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBxO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgfSkoKTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiBhIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIHZhbHVlIG9mIEJpZ051bWJlciBuIGluIGZpeGVkLXBvaW50IG9yIGV4cG9uZW50aWFsXG4gICAgICAgICAqIG5vdGF0aW9uIHJvdW5kZWQgdG8gdGhlIHNwZWNpZmllZCBkZWNpbWFsIHBsYWNlcyBvciBzaWduaWZpY2FudCBkaWdpdHMuXG4gICAgICAgICAqXG4gICAgICAgICAqIG4gaXMgYSBCaWdOdW1iZXIuXG4gICAgICAgICAqIGkgaXMgdGhlIGluZGV4IG9mIHRoZSBsYXN0IGRpZ2l0IHJlcXVpcmVkIChpLmUuIHRoZSBkaWdpdCB0aGF0IG1heSBiZSByb3VuZGVkIHVwKS5cbiAgICAgICAgICogcm0gaXMgdGhlIHJvdW5kaW5nIG1vZGUuXG4gICAgICAgICAqIGNhbGxlciBpcyBjYWxsZXIgaWQ6IHRvRXhwb25lbnRpYWwgMTksIHRvRml4ZWQgMjAsIHRvRm9ybWF0IDIxLCB0b1ByZWNpc2lvbiAyNC5cbiAgICAgICAgICovXG4gICAgICAgIGZ1bmN0aW9uIGZvcm1hdCggbiwgaSwgcm0sIGNhbGxlciApIHtcbiAgICAgICAgICAgIHZhciBjMCwgZSwgbmUsIGxlbiwgc3RyO1xuXG4gICAgICAgICAgICBybSA9IHJtICE9IG51bGwgJiYgaXNWYWxpZEludCggcm0sIDAsIDgsIGNhbGxlciwgcm91bmRpbmdNb2RlIClcbiAgICAgICAgICAgICAgPyBybSB8IDAgOiBST1VORElOR19NT0RFO1xuXG4gICAgICAgICAgICBpZiAoICFuLmMgKSByZXR1cm4gbi50b1N0cmluZygpO1xuICAgICAgICAgICAgYzAgPSBuLmNbMF07XG4gICAgICAgICAgICBuZSA9IG4uZTtcblxuICAgICAgICAgICAgaWYgKCBpID09IG51bGwgKSB7XG4gICAgICAgICAgICAgICAgc3RyID0gY29lZmZUb1N0cmluZyggbi5jICk7XG4gICAgICAgICAgICAgICAgc3RyID0gY2FsbGVyID09IDE5IHx8IGNhbGxlciA9PSAyNCAmJiBuZSA8PSBUT19FWFBfTkVHXG4gICAgICAgICAgICAgICAgICA/IHRvRXhwb25lbnRpYWwoIHN0ciwgbmUgKVxuICAgICAgICAgICAgICAgICAgOiB0b0ZpeGVkUG9pbnQoIHN0ciwgbmUgKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgbiA9IHJvdW5kKCBuZXcgQmlnTnVtYmVyKG4pLCBpLCBybSApO1xuXG4gICAgICAgICAgICAgICAgLy8gbi5lIG1heSBoYXZlIGNoYW5nZWQgaWYgdGhlIHZhbHVlIHdhcyByb3VuZGVkIHVwLlxuICAgICAgICAgICAgICAgIGUgPSBuLmU7XG5cbiAgICAgICAgICAgICAgICBzdHIgPSBjb2VmZlRvU3RyaW5nKCBuLmMgKTtcbiAgICAgICAgICAgICAgICBsZW4gPSBzdHIubGVuZ3RoO1xuXG4gICAgICAgICAgICAgICAgLy8gdG9QcmVjaXNpb24gcmV0dXJucyBleHBvbmVudGlhbCBub3RhdGlvbiBpZiB0aGUgbnVtYmVyIG9mIHNpZ25pZmljYW50IGRpZ2l0c1xuICAgICAgICAgICAgICAgIC8vIHNwZWNpZmllZCBpcyBsZXNzIHRoYW4gdGhlIG51bWJlciBvZiBkaWdpdHMgbmVjZXNzYXJ5IHRvIHJlcHJlc2VudCB0aGUgaW50ZWdlclxuICAgICAgICAgICAgICAgIC8vIHBhcnQgb2YgdGhlIHZhbHVlIGluIGZpeGVkLXBvaW50IG5vdGF0aW9uLlxuXG4gICAgICAgICAgICAgICAgLy8gRXhwb25lbnRpYWwgbm90YXRpb24uXG4gICAgICAgICAgICAgICAgaWYgKCBjYWxsZXIgPT0gMTkgfHwgY2FsbGVyID09IDI0ICYmICggaSA8PSBlIHx8IGUgPD0gVE9fRVhQX05FRyApICkge1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIEFwcGVuZCB6ZXJvcz9cbiAgICAgICAgICAgICAgICAgICAgZm9yICggOyBsZW4gPCBpOyBzdHIgKz0gJzAnLCBsZW4rKyApO1xuICAgICAgICAgICAgICAgICAgICBzdHIgPSB0b0V4cG9uZW50aWFsKCBzdHIsIGUgKTtcblxuICAgICAgICAgICAgICAgIC8vIEZpeGVkLXBvaW50IG5vdGF0aW9uLlxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGkgLT0gbmU7XG4gICAgICAgICAgICAgICAgICAgIHN0ciA9IHRvRml4ZWRQb2ludCggc3RyLCBlICk7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gQXBwZW5kIHplcm9zP1xuICAgICAgICAgICAgICAgICAgICBpZiAoIGUgKyAxID4gbGVuICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCAtLWkgPiAwICkgZm9yICggc3RyICs9ICcuJzsgaS0tOyBzdHIgKz0gJzAnICk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpICs9IGUgLSBsZW47XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIGkgPiAwICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICggZSArIDEgPT0gbGVuICkgc3RyICs9ICcuJztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgKCA7IGktLTsgc3RyICs9ICcwJyApO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gbi5zIDwgMCAmJiBjMCA/ICctJyArIHN0ciA6IHN0cjtcbiAgICAgICAgfVxuXG5cbiAgICAgICAgLy8gSGFuZGxlIEJpZ051bWJlci5tYXggYW5kIEJpZ051bWJlci5taW4uXG4gICAgICAgIGZ1bmN0aW9uIG1heE9yTWluKCBhcmdzLCBtZXRob2QgKSB7XG4gICAgICAgICAgICB2YXIgbSwgbixcbiAgICAgICAgICAgICAgICBpID0gMDtcblxuICAgICAgICAgICAgaWYgKCBpc0FycmF5KCBhcmdzWzBdICkgKSBhcmdzID0gYXJnc1swXTtcbiAgICAgICAgICAgIG0gPSBuZXcgQmlnTnVtYmVyKCBhcmdzWzBdICk7XG5cbiAgICAgICAgICAgIGZvciAoIDsgKytpIDwgYXJncy5sZW5ndGg7ICkge1xuICAgICAgICAgICAgICAgIG4gPSBuZXcgQmlnTnVtYmVyKCBhcmdzW2ldICk7XG5cbiAgICAgICAgICAgICAgICAvLyBJZiBhbnkgbnVtYmVyIGlzIE5hTiwgcmV0dXJuIE5hTi5cbiAgICAgICAgICAgICAgICBpZiAoICFuLnMgKSB7XG4gICAgICAgICAgICAgICAgICAgIG0gPSBuO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCBtZXRob2QuY2FsbCggbSwgbiApICkge1xuICAgICAgICAgICAgICAgICAgICBtID0gbjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBtO1xuICAgICAgICB9XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gdHJ1ZSBpZiBuIGlzIGFuIGludGVnZXIgaW4gcmFuZ2UsIG90aGVyd2lzZSB0aHJvdy5cbiAgICAgICAgICogVXNlIGZvciBhcmd1bWVudCB2YWxpZGF0aW9uIHdoZW4gRVJST1JTIGlzIHRydWUuXG4gICAgICAgICAqL1xuICAgICAgICBmdW5jdGlvbiBpbnRWYWxpZGF0b3JXaXRoRXJyb3JzKCBuLCBtaW4sIG1heCwgY2FsbGVyLCBuYW1lICkge1xuICAgICAgICAgICAgaWYgKCBuIDwgbWluIHx8IG4gPiBtYXggfHwgbiAhPSB0cnVuY2F0ZShuKSApIHtcbiAgICAgICAgICAgICAgICByYWlzZSggY2FsbGVyLCAoIG5hbWUgfHwgJ2RlY2ltYWwgcGxhY2VzJyApICtcbiAgICAgICAgICAgICAgICAgICggbiA8IG1pbiB8fCBuID4gbWF4ID8gJyBvdXQgb2YgcmFuZ2UnIDogJyBub3QgYW4gaW50ZWdlcicgKSwgbiApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogU3RyaXAgdHJhaWxpbmcgemVyb3MsIGNhbGN1bGF0ZSBiYXNlIDEwIGV4cG9uZW50IGFuZCBjaGVjayBhZ2FpbnN0IE1JTl9FWFAgYW5kIE1BWF9FWFAuXG4gICAgICAgICAqIENhbGxlZCBieSBtaW51cywgcGx1cyBhbmQgdGltZXMuXG4gICAgICAgICAqL1xuICAgICAgICBmdW5jdGlvbiBub3JtYWxpc2UoIG4sIGMsIGUgKSB7XG4gICAgICAgICAgICB2YXIgaSA9IDEsXG4gICAgICAgICAgICAgICAgaiA9IGMubGVuZ3RoO1xuXG4gICAgICAgICAgICAgLy8gUmVtb3ZlIHRyYWlsaW5nIHplcm9zLlxuICAgICAgICAgICAgZm9yICggOyAhY1stLWpdOyBjLnBvcCgpICk7XG5cbiAgICAgICAgICAgIC8vIENhbGN1bGF0ZSB0aGUgYmFzZSAxMCBleHBvbmVudC4gRmlyc3QgZ2V0IHRoZSBudW1iZXIgb2YgZGlnaXRzIG9mIGNbMF0uXG4gICAgICAgICAgICBmb3IgKCBqID0gY1swXTsgaiA+PSAxMDsgaiAvPSAxMCwgaSsrICk7XG5cbiAgICAgICAgICAgIC8vIE92ZXJmbG93P1xuICAgICAgICAgICAgaWYgKCAoIGUgPSBpICsgZSAqIExPR19CQVNFIC0gMSApID4gTUFYX0VYUCApIHtcblxuICAgICAgICAgICAgICAgIC8vIEluZmluaXR5LlxuICAgICAgICAgICAgICAgIG4uYyA9IG4uZSA9IG51bGw7XG5cbiAgICAgICAgICAgIC8vIFVuZGVyZmxvdz9cbiAgICAgICAgICAgIH0gZWxzZSBpZiAoIGUgPCBNSU5fRVhQICkge1xuXG4gICAgICAgICAgICAgICAgLy8gWmVyby5cbiAgICAgICAgICAgICAgICBuLmMgPSBbIG4uZSA9IDAgXTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgbi5lID0gZTtcbiAgICAgICAgICAgICAgICBuLmMgPSBjO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gbjtcbiAgICAgICAgfVxuXG5cbiAgICAgICAgLy8gSGFuZGxlIHZhbHVlcyB0aGF0IGZhaWwgdGhlIHZhbGlkaXR5IHRlc3QgaW4gQmlnTnVtYmVyLlxuICAgICAgICBwYXJzZU51bWVyaWMgPSAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIGJhc2VQcmVmaXggPSAvXigtPykwKFt4Ym9dKS9pLFxuICAgICAgICAgICAgICAgIGRvdEFmdGVyID0gL14oW14uXSspXFwuJC8sXG4gICAgICAgICAgICAgICAgZG90QmVmb3JlID0gL15cXC4oW14uXSspJC8sXG4gICAgICAgICAgICAgICAgaXNJbmZpbml0eU9yTmFOID0gL14tPyhJbmZpbml0eXxOYU4pJC8sXG4gICAgICAgICAgICAgICAgd2hpdGVzcGFjZU9yUGx1cyA9IC9eXFxzKlxcK3xeXFxzK3xcXHMrJC9nO1xuXG4gICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24gKCB4LCBzdHIsIG51bSwgYiApIHtcbiAgICAgICAgICAgICAgICB2YXIgYmFzZSxcbiAgICAgICAgICAgICAgICAgICAgcyA9IG51bSA/IHN0ciA6IHN0ci5yZXBsYWNlKCB3aGl0ZXNwYWNlT3JQbHVzLCAnJyApO1xuXG4gICAgICAgICAgICAgICAgLy8gTm8gZXhjZXB0aW9uIG9uIMKxSW5maW5pdHkgb3IgTmFOLlxuICAgICAgICAgICAgICAgIGlmICggaXNJbmZpbml0eU9yTmFOLnRlc3QocykgKSB7XG4gICAgICAgICAgICAgICAgICAgIHgucyA9IGlzTmFOKHMpID8gbnVsbCA6IHMgPCAwID8gLTEgOiAxO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICggIW51bSApIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYmFzZVByZWZpeCA9IC9eKC0/KTAoW3hib10pKD89XFx3W1xcdy5dKiQpL2lcbiAgICAgICAgICAgICAgICAgICAgICAgIHMgPSBzLnJlcGxhY2UoIGJhc2VQcmVmaXgsIGZ1bmN0aW9uICggbSwgcDEsIHAyICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhc2UgPSAoIHAyID0gcDIudG9Mb3dlckNhc2UoKSApID09ICd4JyA/IDE2IDogcDIgPT0gJ2InID8gMiA6IDg7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuICFiIHx8IGIgPT0gYmFzZSA/IHAxIDogbTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoYikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhc2UgPSBiO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gRS5nLiAnMS4nIHRvICcxJywgJy4xJyB0byAnMC4xJ1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHMgPSBzLnJlcGxhY2UoIGRvdEFmdGVyLCAnJDEnICkucmVwbGFjZSggZG90QmVmb3JlLCAnMC4kMScgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCBzdHIgIT0gcyApIHJldHVybiBuZXcgQmlnTnVtYmVyKCBzLCBiYXNlICk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAvLyAnbmV3IEJpZ051bWJlcigpIG5vdCBhIG51bWJlcjoge259J1xuICAgICAgICAgICAgICAgICAgICAvLyAnbmV3IEJpZ051bWJlcigpIG5vdCBhIGJhc2Uge2J9IG51bWJlcjoge259J1xuICAgICAgICAgICAgICAgICAgICBpZiAoRVJST1JTKSByYWlzZSggaWQsICdub3QgYScgKyAoIGIgPyAnIGJhc2UgJyArIGIgOiAnJyApICsgJyBudW1iZXInLCBzdHIgKTtcbiAgICAgICAgICAgICAgICAgICAgeC5zID0gbnVsbDtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB4LmMgPSB4LmUgPSBudWxsO1xuICAgICAgICAgICAgICAgIGlkID0gMDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSkoKTtcblxuXG4gICAgICAgIC8vIFRocm93IGEgQmlnTnVtYmVyIEVycm9yLlxuICAgICAgICBmdW5jdGlvbiByYWlzZSggY2FsbGVyLCBtc2csIHZhbCApIHtcbiAgICAgICAgICAgIHZhciBlcnJvciA9IG5ldyBFcnJvciggW1xuICAgICAgICAgICAgICAgICduZXcgQmlnTnVtYmVyJywgICAgIC8vIDBcbiAgICAgICAgICAgICAgICAnY21wJywgICAgICAgICAgICAgICAvLyAxXG4gICAgICAgICAgICAgICAgJ2NvbmZpZycsICAgICAgICAgICAgLy8gMlxuICAgICAgICAgICAgICAgICdkaXYnLCAgICAgICAgICAgICAgIC8vIDNcbiAgICAgICAgICAgICAgICAnZGl2VG9JbnQnLCAgICAgICAgICAvLyA0XG4gICAgICAgICAgICAgICAgJ2VxJywgICAgICAgICAgICAgICAgLy8gNVxuICAgICAgICAgICAgICAgICdndCcsICAgICAgICAgICAgICAgIC8vIDZcbiAgICAgICAgICAgICAgICAnZ3RlJywgICAgICAgICAgICAgICAvLyA3XG4gICAgICAgICAgICAgICAgJ2x0JywgICAgICAgICAgICAgICAgLy8gOFxuICAgICAgICAgICAgICAgICdsdGUnLCAgICAgICAgICAgICAgIC8vIDlcbiAgICAgICAgICAgICAgICAnbWludXMnLCAgICAgICAgICAgICAvLyAxMFxuICAgICAgICAgICAgICAgICdtb2QnLCAgICAgICAgICAgICAgIC8vIDExXG4gICAgICAgICAgICAgICAgJ3BsdXMnLCAgICAgICAgICAgICAgLy8gMTJcbiAgICAgICAgICAgICAgICAncHJlY2lzaW9uJywgICAgICAgICAvLyAxM1xuICAgICAgICAgICAgICAgICdyYW5kb20nLCAgICAgICAgICAgIC8vIDE0XG4gICAgICAgICAgICAgICAgJ3JvdW5kJywgICAgICAgICAgICAgLy8gMTVcbiAgICAgICAgICAgICAgICAnc2hpZnQnLCAgICAgICAgICAgICAvLyAxNlxuICAgICAgICAgICAgICAgICd0aW1lcycsICAgICAgICAgICAgIC8vIDE3XG4gICAgICAgICAgICAgICAgJ3RvRGlnaXRzJywgICAgICAgICAgLy8gMThcbiAgICAgICAgICAgICAgICAndG9FeHBvbmVudGlhbCcsICAgICAvLyAxOVxuICAgICAgICAgICAgICAgICd0b0ZpeGVkJywgICAgICAgICAgIC8vIDIwXG4gICAgICAgICAgICAgICAgJ3RvRm9ybWF0JywgICAgICAgICAgLy8gMjFcbiAgICAgICAgICAgICAgICAndG9GcmFjdGlvbicsICAgICAgICAvLyAyMlxuICAgICAgICAgICAgICAgICdwb3cnLCAgICAgICAgICAgICAgIC8vIDIzXG4gICAgICAgICAgICAgICAgJ3RvUHJlY2lzaW9uJywgICAgICAgLy8gMjRcbiAgICAgICAgICAgICAgICAndG9TdHJpbmcnLCAgICAgICAgICAvLyAyNVxuICAgICAgICAgICAgICAgICdCaWdOdW1iZXInICAgICAgICAgIC8vIDI2XG4gICAgICAgICAgICBdW2NhbGxlcl0gKyAnKCkgJyArIG1zZyArICc6ICcgKyB2YWwgKTtcblxuICAgICAgICAgICAgZXJyb3IubmFtZSA9ICdCaWdOdW1iZXIgRXJyb3InO1xuICAgICAgICAgICAgaWQgPSAwO1xuICAgICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgIH1cblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJvdW5kIHggdG8gc2Qgc2lnbmlmaWNhbnQgZGlnaXRzIHVzaW5nIHJvdW5kaW5nIG1vZGUgcm0uIENoZWNrIGZvciBvdmVyL3VuZGVyLWZsb3cuXG4gICAgICAgICAqIElmIHIgaXMgdHJ1dGh5LCBpdCBpcyBrbm93biB0aGF0IHRoZXJlIGFyZSBtb3JlIGRpZ2l0cyBhZnRlciB0aGUgcm91bmRpbmcgZGlnaXQuXG4gICAgICAgICAqL1xuICAgICAgICBmdW5jdGlvbiByb3VuZCggeCwgc2QsIHJtLCByICkge1xuICAgICAgICAgICAgdmFyIGQsIGksIGosIGssIG4sIG5pLCByZCxcbiAgICAgICAgICAgICAgICB4YyA9IHguYyxcbiAgICAgICAgICAgICAgICBwb3dzMTAgPSBQT1dTX1RFTjtcblxuICAgICAgICAgICAgLy8gaWYgeCBpcyBub3QgSW5maW5pdHkgb3IgTmFOLi4uXG4gICAgICAgICAgICBpZiAoeGMpIHtcblxuICAgICAgICAgICAgICAgIC8vIHJkIGlzIHRoZSByb3VuZGluZyBkaWdpdCwgaS5lLiB0aGUgZGlnaXQgYWZ0ZXIgdGhlIGRpZ2l0IHRoYXQgbWF5IGJlIHJvdW5kZWQgdXAuXG4gICAgICAgICAgICAgICAgLy8gbiBpcyBhIGJhc2UgMWUxNCBudW1iZXIsIHRoZSB2YWx1ZSBvZiB0aGUgZWxlbWVudCBvZiBhcnJheSB4LmMgY29udGFpbmluZyByZC5cbiAgICAgICAgICAgICAgICAvLyBuaSBpcyB0aGUgaW5kZXggb2YgbiB3aXRoaW4geC5jLlxuICAgICAgICAgICAgICAgIC8vIGQgaXMgdGhlIG51bWJlciBvZiBkaWdpdHMgb2Ygbi5cbiAgICAgICAgICAgICAgICAvLyBpIGlzIHRoZSBpbmRleCBvZiByZCB3aXRoaW4gbiBpbmNsdWRpbmcgbGVhZGluZyB6ZXJvcy5cbiAgICAgICAgICAgICAgICAvLyBqIGlzIHRoZSBhY3R1YWwgaW5kZXggb2YgcmQgd2l0aGluIG4gKGlmIDwgMCwgcmQgaXMgYSBsZWFkaW5nIHplcm8pLlxuICAgICAgICAgICAgICAgIG91dDoge1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIEdldCB0aGUgbnVtYmVyIG9mIGRpZ2l0cyBvZiB0aGUgZmlyc3QgZWxlbWVudCBvZiB4Yy5cbiAgICAgICAgICAgICAgICAgICAgZm9yICggZCA9IDEsIGsgPSB4Y1swXTsgayA+PSAxMDsgayAvPSAxMCwgZCsrICk7XG4gICAgICAgICAgICAgICAgICAgIGkgPSBzZCAtIGQ7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gSWYgdGhlIHJvdW5kaW5nIGRpZ2l0IGlzIGluIHRoZSBmaXJzdCBlbGVtZW50IG9mIHhjLi4uXG4gICAgICAgICAgICAgICAgICAgIGlmICggaSA8IDAgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpICs9IExPR19CQVNFO1xuICAgICAgICAgICAgICAgICAgICAgICAgaiA9IHNkO1xuICAgICAgICAgICAgICAgICAgICAgICAgbiA9IHhjWyBuaSA9IDAgXTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gR2V0IHRoZSByb3VuZGluZyBkaWdpdCBhdCBpbmRleCBqIG9mIG4uXG4gICAgICAgICAgICAgICAgICAgICAgICByZCA9IG4gLyBwb3dzMTBbIGQgLSBqIC0gMSBdICUgMTAgfCAwO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgbmkgPSBtYXRoY2VpbCggKCBpICsgMSApIC8gTE9HX0JBU0UgKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCBuaSA+PSB4Yy5sZW5ndGggKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocikge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE5lZWRlZCBieSBzcXJ0LlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgKCA7IHhjLmxlbmd0aCA8PSBuaTsgeGMucHVzaCgwKSApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuID0gcmQgPSAwO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkID0gMTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaSAlPSBMT0dfQkFTRTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaiA9IGkgLSBMT0dfQkFTRSArIDE7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWsgb3V0O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbiA9IGsgPSB4Y1tuaV07XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBHZXQgdGhlIG51bWJlciBvZiBkaWdpdHMgb2Ygbi5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgKCBkID0gMTsgayA+PSAxMDsgayAvPSAxMCwgZCsrICk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBHZXQgdGhlIGluZGV4IG9mIHJkIHdpdGhpbiBuLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGkgJT0gTE9HX0JBU0U7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBHZXQgdGhlIGluZGV4IG9mIHJkIHdpdGhpbiBuLCBhZGp1c3RlZCBmb3IgbGVhZGluZyB6ZXJvcy5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBUaGUgbnVtYmVyIG9mIGxlYWRpbmcgemVyb3Mgb2YgbiBpcyBnaXZlbiBieSBMT0dfQkFTRSAtIGQuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaiA9IGkgLSBMT0dfQkFTRSArIGQ7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBHZXQgdGhlIHJvdW5kaW5nIGRpZ2l0IGF0IGluZGV4IGogb2Ygbi5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZCA9IGogPCAwID8gMCA6IG4gLyBwb3dzMTBbIGQgLSBqIC0gMSBdICUgMTAgfCAwO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgciA9IHIgfHwgc2QgPCAwIHx8XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gQXJlIHRoZXJlIGFueSBub24temVybyBkaWdpdHMgYWZ0ZXIgdGhlIHJvdW5kaW5nIGRpZ2l0P1xuICAgICAgICAgICAgICAgICAgICAvLyBUaGUgZXhwcmVzc2lvbiAgbiAlIHBvd3MxMFsgZCAtIGogLSAxIF0gIHJldHVybnMgYWxsIGRpZ2l0cyBvZiBuIHRvIHRoZSByaWdodFxuICAgICAgICAgICAgICAgICAgICAvLyBvZiB0aGUgZGlnaXQgYXQgaiwgZS5nLiBpZiBuIGlzIDkwODcxNCBhbmQgaiBpcyAyLCB0aGUgZXhwcmVzc2lvbiBnaXZlcyA3MTQuXG4gICAgICAgICAgICAgICAgICAgICAgeGNbbmkgKyAxXSAhPSBudWxsIHx8ICggaiA8IDAgPyBuIDogbiAlIHBvd3MxMFsgZCAtIGogLSAxIF0gKTtcblxuICAgICAgICAgICAgICAgICAgICByID0gcm0gPCA0XG4gICAgICAgICAgICAgICAgICAgICAgPyAoIHJkIHx8IHIgKSAmJiAoIHJtID09IDAgfHwgcm0gPT0gKCB4LnMgPCAwID8gMyA6IDIgKSApXG4gICAgICAgICAgICAgICAgICAgICAgOiByZCA+IDUgfHwgcmQgPT0gNSAmJiAoIHJtID09IDQgfHwgciB8fCBybSA9PSA2ICYmXG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIENoZWNrIHdoZXRoZXIgdGhlIGRpZ2l0IHRvIHRoZSBsZWZ0IG9mIHRoZSByb3VuZGluZyBkaWdpdCBpcyBvZGQuXG4gICAgICAgICAgICAgICAgICAgICAgICAoICggaSA+IDAgPyBqID4gMCA/IG4gLyBwb3dzMTBbIGQgLSBqIF0gOiAwIDogeGNbbmkgLSAxXSApICUgMTAgKSAmIDEgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgcm0gPT0gKCB4LnMgPCAwID8gOCA6IDcgKSApO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmICggc2QgPCAxIHx8ICF4Y1swXSApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHhjLmxlbmd0aCA9IDA7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBDb252ZXJ0IHNkIHRvIGRlY2ltYWwgcGxhY2VzLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNkIC09IHguZSArIDE7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyAxLCAwLjEsIDAuMDEsIDAuMDAxLCAwLjAwMDEgZXRjLlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhjWzBdID0gcG93czEwWyBzZCAlIExPR19CQVNFIF07XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgeC5lID0gLXNkIHx8IDA7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gWmVyby5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB4Y1swXSA9IHguZSA9IDA7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB4O1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gUmVtb3ZlIGV4Y2VzcyBkaWdpdHMuXG4gICAgICAgICAgICAgICAgICAgIGlmICggaSA9PSAwICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgeGMubGVuZ3RoID0gbmk7XG4gICAgICAgICAgICAgICAgICAgICAgICBrID0gMTtcbiAgICAgICAgICAgICAgICAgICAgICAgIG5pLS07XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB4Yy5sZW5ndGggPSBuaSArIDE7XG4gICAgICAgICAgICAgICAgICAgICAgICBrID0gcG93czEwWyBMT0dfQkFTRSAtIGkgXTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRS5nLiA1NjcwMCBiZWNvbWVzIDU2MDAwIGlmIDcgaXMgdGhlIHJvdW5kaW5nIGRpZ2l0LlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gaiA+IDAgbWVhbnMgaSA+IG51bWJlciBvZiBsZWFkaW5nIHplcm9zIG9mIG4uXG4gICAgICAgICAgICAgICAgICAgICAgICB4Y1tuaV0gPSBqID4gMCA/IG1hdGhmbG9vciggbiAvIHBvd3MxMFsgZCAtIGogXSAlIHBvd3MxMFtqXSApICogayA6IDA7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAvLyBSb3VuZCB1cD9cbiAgICAgICAgICAgICAgICAgICAgaWYgKHIpIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgZm9yICggOyA7ICkge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gSWYgdGhlIGRpZ2l0IHRvIGJlIHJvdW5kZWQgdXAgaXMgaW4gdGhlIGZpcnN0IGVsZW1lbnQgb2YgeGMuLi5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIG5pID09IDAgKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaSB3aWxsIGJlIHRoZSBsZW5ndGggb2YgeGNbMF0gYmVmb3JlIGsgaXMgYWRkZWQuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoIGkgPSAxLCBqID0geGNbMF07IGogPj0gMTA7IGogLz0gMTAsIGkrKyApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBqID0geGNbMF0gKz0gaztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yICggayA9IDE7IGogPj0gMTA7IGogLz0gMTAsIGsrKyApO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGlmIGkgIT0gayB0aGUgbGVuZ3RoIGhhcyBpbmNyZWFzZWQuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICggaSAhPSBrICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeC5lKys7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoIHhjWzBdID09IEJBU0UgKSB4Y1swXSA9IDE7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4Y1tuaV0gKz0gaztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCB4Y1tuaV0gIT0gQkFTRSApIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4Y1tuaS0tXSA9IDA7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGsgPSAxO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIFJlbW92ZSB0cmFpbGluZyB6ZXJvcy5cbiAgICAgICAgICAgICAgICAgICAgZm9yICggaSA9IHhjLmxlbmd0aDsgeGNbLS1pXSA9PT0gMDsgeGMucG9wKCkgKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBPdmVyZmxvdz8gSW5maW5pdHkuXG4gICAgICAgICAgICAgICAgaWYgKCB4LmUgPiBNQVhfRVhQICkge1xuICAgICAgICAgICAgICAgICAgICB4LmMgPSB4LmUgPSBudWxsO1xuXG4gICAgICAgICAgICAgICAgLy8gVW5kZXJmbG93PyBaZXJvLlxuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoIHguZSA8IE1JTl9FWFAgKSB7XG4gICAgICAgICAgICAgICAgICAgIHguYyA9IFsgeC5lID0gMCBdO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHg7XG4gICAgICAgIH1cblxuXG4gICAgICAgIC8vIFBST1RPVFlQRS9JTlNUQU5DRSBNRVRIT0RTXG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gYSBuZXcgQmlnTnVtYmVyIHdob3NlIHZhbHVlIGlzIHRoZSBhYnNvbHV0ZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlci5cbiAgICAgICAgICovXG4gICAgICAgIFAuYWJzb2x1dGVWYWx1ZSA9IFAuYWJzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHggPSBuZXcgQmlnTnVtYmVyKHRoaXMpO1xuICAgICAgICAgICAgaWYgKCB4LnMgPCAwICkgeC5zID0gMTtcbiAgICAgICAgICAgIHJldHVybiB4O1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIGEgbmV3IEJpZ051bWJlciB3aG9zZSB2YWx1ZSBpcyB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgcm91bmRlZCB0byBhIHdob2xlXG4gICAgICAgICAqIG51bWJlciBpbiB0aGUgZGlyZWN0aW9uIG9mIEluZmluaXR5LlxuICAgICAgICAgKi9cbiAgICAgICAgUC5jZWlsID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHJvdW5kKCBuZXcgQmlnTnVtYmVyKHRoaXMpLCB0aGlzLmUgKyAxLCAyICk7XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm5cbiAgICAgICAgICogMSBpZiB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgaXMgZ3JlYXRlciB0aGFuIHRoZSB2YWx1ZSBvZiBCaWdOdW1iZXIoeSwgYiksXG4gICAgICAgICAqIC0xIGlmIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlciBpcyBsZXNzIHRoYW4gdGhlIHZhbHVlIG9mIEJpZ051bWJlcih5LCBiKSxcbiAgICAgICAgICogMCBpZiB0aGV5IGhhdmUgdGhlIHNhbWUgdmFsdWUsXG4gICAgICAgICAqIG9yIG51bGwgaWYgdGhlIHZhbHVlIG9mIGVpdGhlciBpcyBOYU4uXG4gICAgICAgICAqL1xuICAgICAgICBQLmNvbXBhcmVkVG8gPSBQLmNtcCA9IGZ1bmN0aW9uICggeSwgYiApIHtcbiAgICAgICAgICAgIGlkID0gMTtcbiAgICAgICAgICAgIHJldHVybiBjb21wYXJlKCB0aGlzLCBuZXcgQmlnTnVtYmVyKCB5LCBiICkgKTtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiB0aGUgbnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzIG9mIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlciwgb3IgbnVsbCBpZiB0aGUgdmFsdWVcbiAgICAgICAgICogb2YgdGhpcyBCaWdOdW1iZXIgaXMgwrFJbmZpbml0eSBvciBOYU4uXG4gICAgICAgICAqL1xuICAgICAgICBQLmRlY2ltYWxQbGFjZXMgPSBQLmRwID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIG4sIHYsXG4gICAgICAgICAgICAgICAgYyA9IHRoaXMuYztcblxuICAgICAgICAgICAgaWYgKCAhYyApIHJldHVybiBudWxsO1xuICAgICAgICAgICAgbiA9ICggKCB2ID0gYy5sZW5ndGggLSAxICkgLSBiaXRGbG9vciggdGhpcy5lIC8gTE9HX0JBU0UgKSApICogTE9HX0JBU0U7XG5cbiAgICAgICAgICAgIC8vIFN1YnRyYWN0IHRoZSBudW1iZXIgb2YgdHJhaWxpbmcgemVyb3Mgb2YgdGhlIGxhc3QgbnVtYmVyLlxuICAgICAgICAgICAgaWYgKCB2ID0gY1t2XSApIGZvciAoIDsgdiAlIDEwID09IDA7IHYgLz0gMTAsIG4tLSApO1xuICAgICAgICAgICAgaWYgKCBuIDwgMCApIG4gPSAwO1xuXG4gICAgICAgICAgICByZXR1cm4gbjtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqICBuIC8gMCA9IElcbiAgICAgICAgICogIG4gLyBOID0gTlxuICAgICAgICAgKiAgbiAvIEkgPSAwXG4gICAgICAgICAqICAwIC8gbiA9IDBcbiAgICAgICAgICogIDAgLyAwID0gTlxuICAgICAgICAgKiAgMCAvIE4gPSBOXG4gICAgICAgICAqICAwIC8gSSA9IDBcbiAgICAgICAgICogIE4gLyBuID0gTlxuICAgICAgICAgKiAgTiAvIDAgPSBOXG4gICAgICAgICAqICBOIC8gTiA9IE5cbiAgICAgICAgICogIE4gLyBJID0gTlxuICAgICAgICAgKiAgSSAvIG4gPSBJXG4gICAgICAgICAqICBJIC8gMCA9IElcbiAgICAgICAgICogIEkgLyBOID0gTlxuICAgICAgICAgKiAgSSAvIEkgPSBOXG4gICAgICAgICAqXG4gICAgICAgICAqIFJldHVybiBhIG5ldyBCaWdOdW1iZXIgd2hvc2UgdmFsdWUgaXMgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIGRpdmlkZWQgYnkgdGhlIHZhbHVlIG9mXG4gICAgICAgICAqIEJpZ051bWJlcih5LCBiKSwgcm91bmRlZCBhY2NvcmRpbmcgdG8gREVDSU1BTF9QTEFDRVMgYW5kIFJPVU5ESU5HX01PREUuXG4gICAgICAgICAqL1xuICAgICAgICBQLmRpdmlkZWRCeSA9IFAuZGl2ID0gZnVuY3Rpb24gKCB5LCBiICkge1xuICAgICAgICAgICAgaWQgPSAzO1xuICAgICAgICAgICAgcmV0dXJuIGRpdiggdGhpcywgbmV3IEJpZ051bWJlciggeSwgYiApLCBERUNJTUFMX1BMQUNFUywgUk9VTkRJTkdfTU9ERSApO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIGEgbmV3IEJpZ051bWJlciB3aG9zZSB2YWx1ZSBpcyB0aGUgaW50ZWdlciBwYXJ0IG9mIGRpdmlkaW5nIHRoZSB2YWx1ZSBvZiB0aGlzXG4gICAgICAgICAqIEJpZ051bWJlciBieSB0aGUgdmFsdWUgb2YgQmlnTnVtYmVyKHksIGIpLlxuICAgICAgICAgKi9cbiAgICAgICAgUC5kaXZpZGVkVG9JbnRlZ2VyQnkgPSBQLmRpdlRvSW50ID0gZnVuY3Rpb24gKCB5LCBiICkge1xuICAgICAgICAgICAgaWQgPSA0O1xuICAgICAgICAgICAgcmV0dXJuIGRpdiggdGhpcywgbmV3IEJpZ051bWJlciggeSwgYiApLCAwLCAxICk7XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gdHJ1ZSBpZiB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgaXMgZXF1YWwgdG8gdGhlIHZhbHVlIG9mIEJpZ051bWJlcih5LCBiKSxcbiAgICAgICAgICogb3RoZXJ3aXNlIHJldHVybnMgZmFsc2UuXG4gICAgICAgICAqL1xuICAgICAgICBQLmVxdWFscyA9IFAuZXEgPSBmdW5jdGlvbiAoIHksIGIgKSB7XG4gICAgICAgICAgICBpZCA9IDU7XG4gICAgICAgICAgICByZXR1cm4gY29tcGFyZSggdGhpcywgbmV3IEJpZ051bWJlciggeSwgYiApICkgPT09IDA7XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gYSBuZXcgQmlnTnVtYmVyIHdob3NlIHZhbHVlIGlzIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlciByb3VuZGVkIHRvIGEgd2hvbGVcbiAgICAgICAgICogbnVtYmVyIGluIHRoZSBkaXJlY3Rpb24gb2YgLUluZmluaXR5LlxuICAgICAgICAgKi9cbiAgICAgICAgUC5mbG9vciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiByb3VuZCggbmV3IEJpZ051bWJlcih0aGlzKSwgdGhpcy5lICsgMSwgMyApO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIHRydWUgaWYgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIGlzIGdyZWF0ZXIgdGhhbiB0aGUgdmFsdWUgb2YgQmlnTnVtYmVyKHksIGIpLFxuICAgICAgICAgKiBvdGhlcndpc2UgcmV0dXJucyBmYWxzZS5cbiAgICAgICAgICovXG4gICAgICAgIFAuZ3JlYXRlclRoYW4gPSBQLmd0ID0gZnVuY3Rpb24gKCB5LCBiICkge1xuICAgICAgICAgICAgaWQgPSA2O1xuICAgICAgICAgICAgcmV0dXJuIGNvbXBhcmUoIHRoaXMsIG5ldyBCaWdOdW1iZXIoIHksIGIgKSApID4gMDtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiB0cnVlIGlmIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlciBpcyBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gdGhlIHZhbHVlIG9mXG4gICAgICAgICAqIEJpZ051bWJlcih5LCBiKSwgb3RoZXJ3aXNlIHJldHVybnMgZmFsc2UuXG4gICAgICAgICAqL1xuICAgICAgICBQLmdyZWF0ZXJUaGFuT3JFcXVhbFRvID0gUC5ndGUgPSBmdW5jdGlvbiAoIHksIGIgKSB7XG4gICAgICAgICAgICBpZCA9IDc7XG4gICAgICAgICAgICByZXR1cm4gKCBiID0gY29tcGFyZSggdGhpcywgbmV3IEJpZ051bWJlciggeSwgYiApICkgKSA9PT0gMSB8fCBiID09PSAwO1xuXG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gdHJ1ZSBpZiB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgaXMgYSBmaW5pdGUgbnVtYmVyLCBvdGhlcndpc2UgcmV0dXJucyBmYWxzZS5cbiAgICAgICAgICovXG4gICAgICAgIFAuaXNGaW5pdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gISF0aGlzLmM7XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gdHJ1ZSBpZiB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgaXMgYW4gaW50ZWdlciwgb3RoZXJ3aXNlIHJldHVybiBmYWxzZS5cbiAgICAgICAgICovXG4gICAgICAgIFAuaXNJbnRlZ2VyID0gUC5pc0ludCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiAhIXRoaXMuYyAmJiBiaXRGbG9vciggdGhpcy5lIC8gTE9HX0JBU0UgKSA+IHRoaXMuYy5sZW5ndGggLSAyO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIHRydWUgaWYgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIGlzIE5hTiwgb3RoZXJ3aXNlIHJldHVybnMgZmFsc2UuXG4gICAgICAgICAqL1xuICAgICAgICBQLmlzTmFOID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuICF0aGlzLnM7XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gdHJ1ZSBpZiB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgaXMgbmVnYXRpdmUsIG90aGVyd2lzZSByZXR1cm5zIGZhbHNlLlxuICAgICAgICAgKi9cbiAgICAgICAgUC5pc05lZ2F0aXZlID0gUC5pc05lZyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnMgPCAwO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIHRydWUgaWYgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIGlzIDAgb3IgLTAsIG90aGVyd2lzZSByZXR1cm5zIGZhbHNlLlxuICAgICAgICAgKi9cbiAgICAgICAgUC5pc1plcm8gPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gISF0aGlzLmMgJiYgdGhpcy5jWzBdID09IDA7XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gdHJ1ZSBpZiB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgaXMgbGVzcyB0aGFuIHRoZSB2YWx1ZSBvZiBCaWdOdW1iZXIoeSwgYiksXG4gICAgICAgICAqIG90aGVyd2lzZSByZXR1cm5zIGZhbHNlLlxuICAgICAgICAgKi9cbiAgICAgICAgUC5sZXNzVGhhbiA9IFAubHQgPSBmdW5jdGlvbiAoIHksIGIgKSB7XG4gICAgICAgICAgICBpZCA9IDg7XG4gICAgICAgICAgICByZXR1cm4gY29tcGFyZSggdGhpcywgbmV3IEJpZ051bWJlciggeSwgYiApICkgPCAwO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIHRydWUgaWYgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIGlzIGxlc3MgdGhhbiBvciBlcXVhbCB0byB0aGUgdmFsdWUgb2ZcbiAgICAgICAgICogQmlnTnVtYmVyKHksIGIpLCBvdGhlcndpc2UgcmV0dXJucyBmYWxzZS5cbiAgICAgICAgICovXG4gICAgICAgIFAubGVzc1RoYW5PckVxdWFsVG8gPSBQLmx0ZSA9IGZ1bmN0aW9uICggeSwgYiApIHtcbiAgICAgICAgICAgIGlkID0gOTtcbiAgICAgICAgICAgIHJldHVybiAoIGIgPSBjb21wYXJlKCB0aGlzLCBuZXcgQmlnTnVtYmVyKCB5LCBiICkgKSApID09PSAtMSB8fCBiID09PSAwO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogIG4gLSAwID0gblxuICAgICAgICAgKiAgbiAtIE4gPSBOXG4gICAgICAgICAqICBuIC0gSSA9IC1JXG4gICAgICAgICAqICAwIC0gbiA9IC1uXG4gICAgICAgICAqICAwIC0gMCA9IDBcbiAgICAgICAgICogIDAgLSBOID0gTlxuICAgICAgICAgKiAgMCAtIEkgPSAtSVxuICAgICAgICAgKiAgTiAtIG4gPSBOXG4gICAgICAgICAqICBOIC0gMCA9IE5cbiAgICAgICAgICogIE4gLSBOID0gTlxuICAgICAgICAgKiAgTiAtIEkgPSBOXG4gICAgICAgICAqICBJIC0gbiA9IElcbiAgICAgICAgICogIEkgLSAwID0gSVxuICAgICAgICAgKiAgSSAtIE4gPSBOXG4gICAgICAgICAqICBJIC0gSSA9IE5cbiAgICAgICAgICpcbiAgICAgICAgICogUmV0dXJuIGEgbmV3IEJpZ051bWJlciB3aG9zZSB2YWx1ZSBpcyB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgbWludXMgdGhlIHZhbHVlIG9mXG4gICAgICAgICAqIEJpZ051bWJlcih5LCBiKS5cbiAgICAgICAgICovXG4gICAgICAgIFAubWludXMgPSBQLnN1YiA9IGZ1bmN0aW9uICggeSwgYiApIHtcbiAgICAgICAgICAgIHZhciBpLCBqLCB0LCB4TFR5LFxuICAgICAgICAgICAgICAgIHggPSB0aGlzLFxuICAgICAgICAgICAgICAgIGEgPSB4LnM7XG5cbiAgICAgICAgICAgIGlkID0gMTA7XG4gICAgICAgICAgICB5ID0gbmV3IEJpZ051bWJlciggeSwgYiApO1xuICAgICAgICAgICAgYiA9IHkucztcblxuICAgICAgICAgICAgLy8gRWl0aGVyIE5hTj9cbiAgICAgICAgICAgIGlmICggIWEgfHwgIWIgKSByZXR1cm4gbmV3IEJpZ051bWJlcihOYU4pO1xuXG4gICAgICAgICAgICAvLyBTaWducyBkaWZmZXI/XG4gICAgICAgICAgICBpZiAoIGEgIT0gYiApIHtcbiAgICAgICAgICAgICAgICB5LnMgPSAtYjtcbiAgICAgICAgICAgICAgICByZXR1cm4geC5wbHVzKHkpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgeGUgPSB4LmUgLyBMT0dfQkFTRSxcbiAgICAgICAgICAgICAgICB5ZSA9IHkuZSAvIExPR19CQVNFLFxuICAgICAgICAgICAgICAgIHhjID0geC5jLFxuICAgICAgICAgICAgICAgIHljID0geS5jO1xuXG4gICAgICAgICAgICBpZiAoICF4ZSB8fCAheWUgKSB7XG5cbiAgICAgICAgICAgICAgICAvLyBFaXRoZXIgSW5maW5pdHk/XG4gICAgICAgICAgICAgICAgaWYgKCAheGMgfHwgIXljICkgcmV0dXJuIHhjID8gKCB5LnMgPSAtYiwgeSApIDogbmV3IEJpZ051bWJlciggeWMgPyB4IDogTmFOICk7XG5cbiAgICAgICAgICAgICAgICAvLyBFaXRoZXIgemVybz9cbiAgICAgICAgICAgICAgICBpZiAoICF4Y1swXSB8fCAheWNbMF0gKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gUmV0dXJuIHkgaWYgeSBpcyBub24temVybywgeCBpZiB4IGlzIG5vbi16ZXJvLCBvciB6ZXJvIGlmIGJvdGggYXJlIHplcm8uXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB5Y1swXSA/ICggeS5zID0gLWIsIHkgKSA6IG5ldyBCaWdOdW1iZXIoIHhjWzBdID8geCA6XG5cbiAgICAgICAgICAgICAgICAgICAgICAvLyBJRUVFIDc1NCAoMjAwOCkgNi4zOiBuIC0gbiA9IC0wIHdoZW4gcm91bmRpbmcgdG8gLUluZmluaXR5XG4gICAgICAgICAgICAgICAgICAgICAgUk9VTkRJTkdfTU9ERSA9PSAzID8gLTAgOiAwICk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB4ZSA9IGJpdEZsb29yKHhlKTtcbiAgICAgICAgICAgIHllID0gYml0Rmxvb3IoeWUpO1xuICAgICAgICAgICAgeGMgPSB4Yy5zbGljZSgpO1xuXG4gICAgICAgICAgICAvLyBEZXRlcm1pbmUgd2hpY2ggaXMgdGhlIGJpZ2dlciBudW1iZXIuXG4gICAgICAgICAgICBpZiAoIGEgPSB4ZSAtIHllICkge1xuXG4gICAgICAgICAgICAgICAgaWYgKCB4TFR5ID0gYSA8IDAgKSB7XG4gICAgICAgICAgICAgICAgICAgIGEgPSAtYTtcbiAgICAgICAgICAgICAgICAgICAgdCA9IHhjO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHllID0geGU7XG4gICAgICAgICAgICAgICAgICAgIHQgPSB5YztcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0LnJldmVyc2UoKTtcblxuICAgICAgICAgICAgICAgIC8vIFByZXBlbmQgemVyb3MgdG8gZXF1YWxpc2UgZXhwb25lbnRzLlxuICAgICAgICAgICAgICAgIGZvciAoIGIgPSBhOyBiLS07IHQucHVzaCgwKSApO1xuICAgICAgICAgICAgICAgIHQucmV2ZXJzZSgpO1xuICAgICAgICAgICAgfSBlbHNlIHtcblxuICAgICAgICAgICAgICAgIC8vIEV4cG9uZW50cyBlcXVhbC4gQ2hlY2sgZGlnaXQgYnkgZGlnaXQuXG4gICAgICAgICAgICAgICAgaiA9ICggeExUeSA9ICggYSA9IHhjLmxlbmd0aCApIDwgKCBiID0geWMubGVuZ3RoICkgKSA/IGEgOiBiO1xuXG4gICAgICAgICAgICAgICAgZm9yICggYSA9IGIgPSAwOyBiIDwgajsgYisrICkge1xuXG4gICAgICAgICAgICAgICAgICAgIGlmICggeGNbYl0gIT0geWNbYl0gKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB4TFR5ID0geGNbYl0gPCB5Y1tiXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyB4IDwgeT8gUG9pbnQgeGMgdG8gdGhlIGFycmF5IG9mIHRoZSBiaWdnZXIgbnVtYmVyLlxuICAgICAgICAgICAgaWYgKHhMVHkpIHQgPSB4YywgeGMgPSB5YywgeWMgPSB0LCB5LnMgPSAteS5zO1xuXG4gICAgICAgICAgICBiID0gKCBqID0geWMubGVuZ3RoICkgLSAoIGkgPSB4Yy5sZW5ndGggKTtcblxuICAgICAgICAgICAgLy8gQXBwZW5kIHplcm9zIHRvIHhjIGlmIHNob3J0ZXIuXG4gICAgICAgICAgICAvLyBObyBuZWVkIHRvIGFkZCB6ZXJvcyB0byB5YyBpZiBzaG9ydGVyIGFzIHN1YnRyYWN0IG9ubHkgbmVlZHMgdG8gc3RhcnQgYXQgeWMubGVuZ3RoLlxuICAgICAgICAgICAgaWYgKCBiID4gMCApIGZvciAoIDsgYi0tOyB4Y1tpKytdID0gMCApO1xuICAgICAgICAgICAgYiA9IEJBU0UgLSAxO1xuXG4gICAgICAgICAgICAvLyBTdWJ0cmFjdCB5YyBmcm9tIHhjLlxuICAgICAgICAgICAgZm9yICggOyBqID4gYTsgKSB7XG5cbiAgICAgICAgICAgICAgICBpZiAoIHhjWy0tal0gPCB5Y1tqXSApIHtcbiAgICAgICAgICAgICAgICAgICAgZm9yICggaSA9IGo7IGkgJiYgIXhjWy0taV07IHhjW2ldID0gYiApO1xuICAgICAgICAgICAgICAgICAgICAtLXhjW2ldO1xuICAgICAgICAgICAgICAgICAgICB4Y1tqXSArPSBCQVNFO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHhjW2pdIC09IHljW2pdO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBSZW1vdmUgbGVhZGluZyB6ZXJvcyBhbmQgYWRqdXN0IGV4cG9uZW50IGFjY29yZGluZ2x5LlxuICAgICAgICAgICAgZm9yICggOyB4Y1swXSA9PSAwOyB4Yy5zaGlmdCgpLCAtLXllICk7XG5cbiAgICAgICAgICAgIC8vIFplcm8/XG4gICAgICAgICAgICBpZiAoICF4Y1swXSApIHtcblxuICAgICAgICAgICAgICAgIC8vIEZvbGxvd2luZyBJRUVFIDc1NCAoMjAwOCkgNi4zLFxuICAgICAgICAgICAgICAgIC8vIG4gLSBuID0gKzAgIGJ1dCAgbiAtIG4gPSAtMCAgd2hlbiByb3VuZGluZyB0b3dhcmRzIC1JbmZpbml0eS5cbiAgICAgICAgICAgICAgICB5LnMgPSBST1VORElOR19NT0RFID09IDMgPyAtMSA6IDE7XG4gICAgICAgICAgICAgICAgeS5jID0gWyB5LmUgPSAwIF07XG4gICAgICAgICAgICAgICAgcmV0dXJuIHk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIE5vIG5lZWQgdG8gY2hlY2sgZm9yIEluZmluaXR5IGFzICt4IC0gK3kgIT0gSW5maW5pdHkgJiYgLXggLSAteSAhPSBJbmZpbml0eVxuICAgICAgICAgICAgLy8gZm9yIGZpbml0ZSB4IGFuZCB5LlxuICAgICAgICAgICAgcmV0dXJuIG5vcm1hbGlzZSggeSwgeGMsIHllICk7XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiAgIG4gJSAwID0gIE5cbiAgICAgICAgICogICBuICUgTiA9ICBOXG4gICAgICAgICAqICAgbiAlIEkgPSAgblxuICAgICAgICAgKiAgIDAgJSBuID0gIDBcbiAgICAgICAgICogIC0wICUgbiA9IC0wXG4gICAgICAgICAqICAgMCAlIDAgPSAgTlxuICAgICAgICAgKiAgIDAgJSBOID0gIE5cbiAgICAgICAgICogICAwICUgSSA9ICAwXG4gICAgICAgICAqICAgTiAlIG4gPSAgTlxuICAgICAgICAgKiAgIE4gJSAwID0gIE5cbiAgICAgICAgICogICBOICUgTiA9ICBOXG4gICAgICAgICAqICAgTiAlIEkgPSAgTlxuICAgICAgICAgKiAgIEkgJSBuID0gIE5cbiAgICAgICAgICogICBJICUgMCA9ICBOXG4gICAgICAgICAqICAgSSAlIE4gPSAgTlxuICAgICAgICAgKiAgIEkgJSBJID0gIE5cbiAgICAgICAgICpcbiAgICAgICAgICogUmV0dXJuIGEgbmV3IEJpZ051bWJlciB3aG9zZSB2YWx1ZSBpcyB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgbW9kdWxvIHRoZSB2YWx1ZSBvZlxuICAgICAgICAgKiBCaWdOdW1iZXIoeSwgYikuIFRoZSByZXN1bHQgZGVwZW5kcyBvbiB0aGUgdmFsdWUgb2YgTU9EVUxPX01PREUuXG4gICAgICAgICAqL1xuICAgICAgICBQLm1vZHVsbyA9IFAubW9kID0gZnVuY3Rpb24gKCB5LCBiICkge1xuICAgICAgICAgICAgdmFyIHEsIHMsXG4gICAgICAgICAgICAgICAgeCA9IHRoaXM7XG5cbiAgICAgICAgICAgIGlkID0gMTE7XG4gICAgICAgICAgICB5ID0gbmV3IEJpZ051bWJlciggeSwgYiApO1xuXG4gICAgICAgICAgICAvLyBSZXR1cm4gTmFOIGlmIHggaXMgSW5maW5pdHkgb3IgTmFOLCBvciB5IGlzIE5hTiBvciB6ZXJvLlxuICAgICAgICAgICAgaWYgKCAheC5jIHx8ICF5LnMgfHwgeS5jICYmICF5LmNbMF0gKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBCaWdOdW1iZXIoTmFOKTtcblxuICAgICAgICAgICAgLy8gUmV0dXJuIHggaWYgeSBpcyBJbmZpbml0eSBvciB4IGlzIHplcm8uXG4gICAgICAgICAgICB9IGVsc2UgaWYgKCAheS5jIHx8IHguYyAmJiAheC5jWzBdICkge1xuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgQmlnTnVtYmVyKHgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoIE1PRFVMT19NT0RFID09IDkgKSB7XG5cbiAgICAgICAgICAgICAgICAvLyBFdWNsaWRpYW4gZGl2aXNpb246IHEgPSBzaWduKHkpICogZmxvb3IoeCAvIGFicyh5KSlcbiAgICAgICAgICAgICAgICAvLyByID0geCAtIHF5ICAgIHdoZXJlICAwIDw9IHIgPCBhYnMoeSlcbiAgICAgICAgICAgICAgICBzID0geS5zO1xuICAgICAgICAgICAgICAgIHkucyA9IDE7XG4gICAgICAgICAgICAgICAgcSA9IGRpdiggeCwgeSwgMCwgMyApO1xuICAgICAgICAgICAgICAgIHkucyA9IHM7XG4gICAgICAgICAgICAgICAgcS5zICo9IHM7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHEgPSBkaXYoIHgsIHksIDAsIE1PRFVMT19NT0RFICk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB4Lm1pbnVzKCBxLnRpbWVzKHkpICk7XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gYSBuZXcgQmlnTnVtYmVyIHdob3NlIHZhbHVlIGlzIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlciBuZWdhdGVkLFxuICAgICAgICAgKiBpLmUuIG11bHRpcGxpZWQgYnkgLTEuXG4gICAgICAgICAqL1xuICAgICAgICBQLm5lZ2F0ZWQgPSBQLm5lZyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciB4ID0gbmV3IEJpZ051bWJlcih0aGlzKTtcbiAgICAgICAgICAgIHgucyA9IC14LnMgfHwgbnVsbDtcbiAgICAgICAgICAgIHJldHVybiB4O1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogIG4gKyAwID0gblxuICAgICAgICAgKiAgbiArIE4gPSBOXG4gICAgICAgICAqICBuICsgSSA9IElcbiAgICAgICAgICogIDAgKyBuID0gblxuICAgICAgICAgKiAgMCArIDAgPSAwXG4gICAgICAgICAqICAwICsgTiA9IE5cbiAgICAgICAgICogIDAgKyBJID0gSVxuICAgICAgICAgKiAgTiArIG4gPSBOXG4gICAgICAgICAqICBOICsgMCA9IE5cbiAgICAgICAgICogIE4gKyBOID0gTlxuICAgICAgICAgKiAgTiArIEkgPSBOXG4gICAgICAgICAqICBJICsgbiA9IElcbiAgICAgICAgICogIEkgKyAwID0gSVxuICAgICAgICAgKiAgSSArIE4gPSBOXG4gICAgICAgICAqICBJICsgSSA9IElcbiAgICAgICAgICpcbiAgICAgICAgICogUmV0dXJuIGEgbmV3IEJpZ051bWJlciB3aG9zZSB2YWx1ZSBpcyB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgcGx1cyB0aGUgdmFsdWUgb2ZcbiAgICAgICAgICogQmlnTnVtYmVyKHksIGIpLlxuICAgICAgICAgKi9cbiAgICAgICAgUC5wbHVzID0gUC5hZGQgPSBmdW5jdGlvbiAoIHksIGIgKSB7XG4gICAgICAgICAgICB2YXIgdCxcbiAgICAgICAgICAgICAgICB4ID0gdGhpcyxcbiAgICAgICAgICAgICAgICBhID0geC5zO1xuXG4gICAgICAgICAgICBpZCA9IDEyO1xuICAgICAgICAgICAgeSA9IG5ldyBCaWdOdW1iZXIoIHksIGIgKTtcbiAgICAgICAgICAgIGIgPSB5LnM7XG5cbiAgICAgICAgICAgIC8vIEVpdGhlciBOYU4/XG4gICAgICAgICAgICBpZiAoICFhIHx8ICFiICkgcmV0dXJuIG5ldyBCaWdOdW1iZXIoTmFOKTtcblxuICAgICAgICAgICAgLy8gU2lnbnMgZGlmZmVyP1xuICAgICAgICAgICAgIGlmICggYSAhPSBiICkge1xuICAgICAgICAgICAgICAgIHkucyA9IC1iO1xuICAgICAgICAgICAgICAgIHJldHVybiB4Lm1pbnVzKHkpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgeGUgPSB4LmUgLyBMT0dfQkFTRSxcbiAgICAgICAgICAgICAgICB5ZSA9IHkuZSAvIExPR19CQVNFLFxuICAgICAgICAgICAgICAgIHhjID0geC5jLFxuICAgICAgICAgICAgICAgIHljID0geS5jO1xuXG4gICAgICAgICAgICBpZiAoICF4ZSB8fCAheWUgKSB7XG5cbiAgICAgICAgICAgICAgICAvLyBSZXR1cm4gwrFJbmZpbml0eSBpZiBlaXRoZXIgwrFJbmZpbml0eS5cbiAgICAgICAgICAgICAgICBpZiAoICF4YyB8fCAheWMgKSByZXR1cm4gbmV3IEJpZ051bWJlciggYSAvIDAgKTtcblxuICAgICAgICAgICAgICAgIC8vIEVpdGhlciB6ZXJvP1xuICAgICAgICAgICAgICAgIC8vIFJldHVybiB5IGlmIHkgaXMgbm9uLXplcm8sIHggaWYgeCBpcyBub24temVybywgb3IgemVybyBpZiBib3RoIGFyZSB6ZXJvLlxuICAgICAgICAgICAgICAgIGlmICggIXhjWzBdIHx8ICF5Y1swXSApIHJldHVybiB5Y1swXSA/IHkgOiBuZXcgQmlnTnVtYmVyKCB4Y1swXSA/IHggOiBhICogMCApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB4ZSA9IGJpdEZsb29yKHhlKTtcbiAgICAgICAgICAgIHllID0gYml0Rmxvb3IoeWUpO1xuICAgICAgICAgICAgeGMgPSB4Yy5zbGljZSgpO1xuXG4gICAgICAgICAgICAvLyBQcmVwZW5kIHplcm9zIHRvIGVxdWFsaXNlIGV4cG9uZW50cy4gRmFzdGVyIHRvIHVzZSByZXZlcnNlIHRoZW4gZG8gdW5zaGlmdHMuXG4gICAgICAgICAgICBpZiAoIGEgPSB4ZSAtIHllICkge1xuICAgICAgICAgICAgICAgIGlmICggYSA+IDAgKSB7XG4gICAgICAgICAgICAgICAgICAgIHllID0geGU7XG4gICAgICAgICAgICAgICAgICAgIHQgPSB5YztcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBhID0gLWE7XG4gICAgICAgICAgICAgICAgICAgIHQgPSB4YztcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0LnJldmVyc2UoKTtcbiAgICAgICAgICAgICAgICBmb3IgKCA7IGEtLTsgdC5wdXNoKDApICk7XG4gICAgICAgICAgICAgICAgdC5yZXZlcnNlKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGEgPSB4Yy5sZW5ndGg7XG4gICAgICAgICAgICBiID0geWMubGVuZ3RoO1xuXG4gICAgICAgICAgICAvLyBQb2ludCB4YyB0byB0aGUgbG9uZ2VyIGFycmF5LCBhbmQgYiB0byB0aGUgc2hvcnRlciBsZW5ndGguXG4gICAgICAgICAgICBpZiAoIGEgLSBiIDwgMCApIHQgPSB5YywgeWMgPSB4YywgeGMgPSB0LCBiID0gYTtcblxuICAgICAgICAgICAgLy8gT25seSBzdGFydCBhZGRpbmcgYXQgeWMubGVuZ3RoIC0gMSBhcyB0aGUgZnVydGhlciBkaWdpdHMgb2YgeGMgY2FuIGJlIGlnbm9yZWQuXG4gICAgICAgICAgICBmb3IgKCBhID0gMDsgYjsgKSB7XG4gICAgICAgICAgICAgICAgYSA9ICggeGNbLS1iXSA9IHhjW2JdICsgeWNbYl0gKyBhICkgLyBCQVNFIHwgMDtcbiAgICAgICAgICAgICAgICB4Y1tiXSAlPSBCQVNFO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoYSkge1xuICAgICAgICAgICAgICAgIHhjLnVuc2hpZnQoYSk7XG4gICAgICAgICAgICAgICAgKyt5ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gTm8gbmVlZCB0byBjaGVjayBmb3IgemVybywgYXMgK3ggKyAreSAhPSAwICYmIC14ICsgLXkgIT0gMFxuICAgICAgICAgICAgLy8geWUgPSBNQVhfRVhQICsgMSBwb3NzaWJsZVxuICAgICAgICAgICAgcmV0dXJuIG5vcm1hbGlzZSggeSwgeGMsIHllICk7XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gdGhlIG51bWJlciBvZiBzaWduaWZpY2FudCBkaWdpdHMgb2YgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyLlxuICAgICAgICAgKlxuICAgICAgICAgKiBbel0ge2Jvb2xlYW58bnVtYmVyfSBXaGV0aGVyIHRvIGNvdW50IGludGVnZXItcGFydCB0cmFpbGluZyB6ZXJvczogdHJ1ZSwgZmFsc2UsIDEgb3IgMC5cbiAgICAgICAgICovXG4gICAgICAgIFAucHJlY2lzaW9uID0gUC5zZCA9IGZ1bmN0aW9uICh6KSB7XG4gICAgICAgICAgICB2YXIgbiwgdixcbiAgICAgICAgICAgICAgICB4ID0gdGhpcyxcbiAgICAgICAgICAgICAgICBjID0geC5jO1xuXG4gICAgICAgICAgICAvLyAncHJlY2lzaW9uKCkgYXJndW1lbnQgbm90IGEgYm9vbGVhbiBvciBiaW5hcnkgZGlnaXQ6IHt6fSdcbiAgICAgICAgICAgIGlmICggeiAhPSBudWxsICYmIHogIT09ICEheiAmJiB6ICE9PSAxICYmIHogIT09IDAgKSB7XG4gICAgICAgICAgICAgICAgaWYgKEVSUk9SUykgcmFpc2UoIDEzLCAnYXJndW1lbnQnICsgbm90Qm9vbCwgeiApO1xuICAgICAgICAgICAgICAgIGlmICggeiAhPSAhIXogKSB6ID0gbnVsbDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCAhYyApIHJldHVybiBudWxsO1xuICAgICAgICAgICAgdiA9IGMubGVuZ3RoIC0gMTtcbiAgICAgICAgICAgIG4gPSB2ICogTE9HX0JBU0UgKyAxO1xuXG4gICAgICAgICAgICBpZiAoIHYgPSBjW3ZdICkge1xuXG4gICAgICAgICAgICAgICAgLy8gU3VidHJhY3QgdGhlIG51bWJlciBvZiB0cmFpbGluZyB6ZXJvcyBvZiB0aGUgbGFzdCBlbGVtZW50LlxuICAgICAgICAgICAgICAgIGZvciAoIDsgdiAlIDEwID09IDA7IHYgLz0gMTAsIG4tLSApO1xuXG4gICAgICAgICAgICAgICAgLy8gQWRkIHRoZSBudW1iZXIgb2YgZGlnaXRzIG9mIHRoZSBmaXJzdCBlbGVtZW50LlxuICAgICAgICAgICAgICAgIGZvciAoIHYgPSBjWzBdOyB2ID49IDEwOyB2IC89IDEwLCBuKysgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCB6ICYmIHguZSArIDEgPiBuICkgbiA9IHguZSArIDE7XG5cbiAgICAgICAgICAgIHJldHVybiBuO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIGEgbmV3IEJpZ051bWJlciB3aG9zZSB2YWx1ZSBpcyB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgcm91bmRlZCB0byBhIG1heGltdW0gb2ZcbiAgICAgICAgICogZHAgZGVjaW1hbCBwbGFjZXMgdXNpbmcgcm91bmRpbmcgbW9kZSBybSwgb3IgdG8gMCBhbmQgUk9VTkRJTkdfTU9ERSByZXNwZWN0aXZlbHkgaWZcbiAgICAgICAgICogb21pdHRlZC5cbiAgICAgICAgICpcbiAgICAgICAgICogW2RwXSB7bnVtYmVyfSBEZWNpbWFsIHBsYWNlcy4gSW50ZWdlciwgMCB0byBNQVggaW5jbHVzaXZlLlxuICAgICAgICAgKiBbcm1dIHtudW1iZXJ9IFJvdW5kaW5nIG1vZGUuIEludGVnZXIsIDAgdG8gOCBpbmNsdXNpdmUuXG4gICAgICAgICAqXG4gICAgICAgICAqICdyb3VuZCgpIGRlY2ltYWwgcGxhY2VzIG91dCBvZiByYW5nZToge2RwfSdcbiAgICAgICAgICogJ3JvdW5kKCkgZGVjaW1hbCBwbGFjZXMgbm90IGFuIGludGVnZXI6IHtkcH0nXG4gICAgICAgICAqICdyb3VuZCgpIHJvdW5kaW5nIG1vZGUgbm90IGFuIGludGVnZXI6IHtybX0nXG4gICAgICAgICAqICdyb3VuZCgpIHJvdW5kaW5nIG1vZGUgb3V0IG9mIHJhbmdlOiB7cm19J1xuICAgICAgICAgKi9cbiAgICAgICAgUC5yb3VuZCA9IGZ1bmN0aW9uICggZHAsIHJtICkge1xuICAgICAgICAgICAgdmFyIG4gPSBuZXcgQmlnTnVtYmVyKHRoaXMpO1xuXG4gICAgICAgICAgICBpZiAoIGRwID09IG51bGwgfHwgaXNWYWxpZEludCggZHAsIDAsIE1BWCwgMTUgKSApIHtcbiAgICAgICAgICAgICAgICByb3VuZCggbiwgfn5kcCArIHRoaXMuZSArIDEsIHJtID09IG51bGwgfHxcbiAgICAgICAgICAgICAgICAgICFpc1ZhbGlkSW50KCBybSwgMCwgOCwgMTUsIHJvdW5kaW5nTW9kZSApID8gUk9VTkRJTkdfTU9ERSA6IHJtIHwgMCApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gbjtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiBhIG5ldyBCaWdOdW1iZXIgd2hvc2UgdmFsdWUgaXMgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIHNoaWZ0ZWQgYnkgayBwbGFjZXNcbiAgICAgICAgICogKHBvd2VycyBvZiAxMCkuIFNoaWZ0IHRvIHRoZSByaWdodCBpZiBuID4gMCwgYW5kIHRvIHRoZSBsZWZ0IGlmIG4gPCAwLlxuICAgICAgICAgKlxuICAgICAgICAgKiBrIHtudW1iZXJ9IEludGVnZXIsIC1NQVhfU0FGRV9JTlRFR0VSIHRvIE1BWF9TQUZFX0lOVEVHRVIgaW5jbHVzaXZlLlxuICAgICAgICAgKlxuICAgICAgICAgKiBJZiBrIGlzIG91dCBvZiByYW5nZSBhbmQgRVJST1JTIGlzIGZhbHNlLCB0aGUgcmVzdWx0IHdpbGwgYmUgwrEwIGlmIGsgPCAwLCBvciDCsUluZmluaXR5XG4gICAgICAgICAqIG90aGVyd2lzZS5cbiAgICAgICAgICpcbiAgICAgICAgICogJ3NoaWZ0KCkgYXJndW1lbnQgbm90IGFuIGludGVnZXI6IHtrfSdcbiAgICAgICAgICogJ3NoaWZ0KCkgYXJndW1lbnQgb3V0IG9mIHJhbmdlOiB7a30nXG4gICAgICAgICAqL1xuICAgICAgICBQLnNoaWZ0ID0gZnVuY3Rpb24gKGspIHtcbiAgICAgICAgICAgIHZhciBuID0gdGhpcztcbiAgICAgICAgICAgIHJldHVybiBpc1ZhbGlkSW50KCBrLCAtTUFYX1NBRkVfSU5URUdFUiwgTUFYX1NBRkVfSU5URUdFUiwgMTYsICdhcmd1bWVudCcgKVxuXG4gICAgICAgICAgICAgIC8vIGsgPCAxZSsyMSwgb3IgdHJ1bmNhdGUoaykgd2lsbCBwcm9kdWNlIGV4cG9uZW50aWFsIG5vdGF0aW9uLlxuICAgICAgICAgICAgICA/IG4udGltZXMoICcxZScgKyB0cnVuY2F0ZShrKSApXG4gICAgICAgICAgICAgIDogbmV3IEJpZ051bWJlciggbi5jICYmIG4uY1swXSAmJiAoIGsgPCAtTUFYX1NBRkVfSU5URUdFUiB8fCBrID4gTUFYX1NBRkVfSU5URUdFUiApXG4gICAgICAgICAgICAgICAgPyBuLnMgKiAoIGsgPCAwID8gMCA6IDEgLyAwIClcbiAgICAgICAgICAgICAgICA6IG4gKTtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqICBzcXJ0KC1uKSA9ICBOXG4gICAgICAgICAqICBzcXJ0KCBOKSA9ICBOXG4gICAgICAgICAqICBzcXJ0KC1JKSA9ICBOXG4gICAgICAgICAqICBzcXJ0KCBJKSA9ICBJXG4gICAgICAgICAqICBzcXJ0KCAwKSA9ICAwXG4gICAgICAgICAqICBzcXJ0KC0wKSA9IC0wXG4gICAgICAgICAqXG4gICAgICAgICAqIFJldHVybiBhIG5ldyBCaWdOdW1iZXIgd2hvc2UgdmFsdWUgaXMgdGhlIHNxdWFyZSByb290IG9mIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlcixcbiAgICAgICAgICogcm91bmRlZCBhY2NvcmRpbmcgdG8gREVDSU1BTF9QTEFDRVMgYW5kIFJPVU5ESU5HX01PREUuXG4gICAgICAgICAqL1xuICAgICAgICBQLnNxdWFyZVJvb3QgPSBQLnNxcnQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgbSwgbiwgciwgcmVwLCB0LFxuICAgICAgICAgICAgICAgIHggPSB0aGlzLFxuICAgICAgICAgICAgICAgIGMgPSB4LmMsXG4gICAgICAgICAgICAgICAgcyA9IHgucyxcbiAgICAgICAgICAgICAgICBlID0geC5lLFxuICAgICAgICAgICAgICAgIGRwID0gREVDSU1BTF9QTEFDRVMgKyA0LFxuICAgICAgICAgICAgICAgIGhhbGYgPSBuZXcgQmlnTnVtYmVyKCcwLjUnKTtcblxuICAgICAgICAgICAgLy8gTmVnYXRpdmUvTmFOL0luZmluaXR5L3plcm8/XG4gICAgICAgICAgICBpZiAoIHMgIT09IDEgfHwgIWMgfHwgIWNbMF0gKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBCaWdOdW1iZXIoICFzIHx8IHMgPCAwICYmICggIWMgfHwgY1swXSApID8gTmFOIDogYyA/IHggOiAxIC8gMCApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBJbml0aWFsIGVzdGltYXRlLlxuICAgICAgICAgICAgcyA9IE1hdGguc3FydCggK3ggKTtcblxuICAgICAgICAgICAgLy8gTWF0aC5zcXJ0IHVuZGVyZmxvdy9vdmVyZmxvdz9cbiAgICAgICAgICAgIC8vIFBhc3MgeCB0byBNYXRoLnNxcnQgYXMgaW50ZWdlciwgdGhlbiBhZGp1c3QgdGhlIGV4cG9uZW50IG9mIHRoZSByZXN1bHQuXG4gICAgICAgICAgICBpZiAoIHMgPT0gMCB8fCBzID09IDEgLyAwICkge1xuICAgICAgICAgICAgICAgIG4gPSBjb2VmZlRvU3RyaW5nKGMpO1xuICAgICAgICAgICAgICAgIGlmICggKCBuLmxlbmd0aCArIGUgKSAlIDIgPT0gMCApIG4gKz0gJzAnO1xuICAgICAgICAgICAgICAgIHMgPSBNYXRoLnNxcnQobik7XG4gICAgICAgICAgICAgICAgZSA9IGJpdEZsb29yKCAoIGUgKyAxICkgLyAyICkgLSAoIGUgPCAwIHx8IGUgJSAyICk7XG5cbiAgICAgICAgICAgICAgICBpZiAoIHMgPT0gMSAvIDAgKSB7XG4gICAgICAgICAgICAgICAgICAgIG4gPSAnMWUnICsgZTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBuID0gcy50b0V4cG9uZW50aWFsKCk7XG4gICAgICAgICAgICAgICAgICAgIG4gPSBuLnNsaWNlKCAwLCBuLmluZGV4T2YoJ2UnKSArIDEgKSArIGU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgciA9IG5ldyBCaWdOdW1iZXIobik7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHIgPSBuZXcgQmlnTnVtYmVyKCBzICsgJycgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gQ2hlY2sgZm9yIHplcm8uXG4gICAgICAgICAgICAvLyByIGNvdWxkIGJlIHplcm8gaWYgTUlOX0VYUCBpcyBjaGFuZ2VkIGFmdGVyIHRoZSB0aGlzIHZhbHVlIHdhcyBjcmVhdGVkLlxuICAgICAgICAgICAgLy8gVGhpcyB3b3VsZCBjYXVzZSBhIGRpdmlzaW9uIGJ5IHplcm8gKHgvdCkgYW5kIGhlbmNlIEluZmluaXR5IGJlbG93LCB3aGljaCB3b3VsZCBjYXVzZVxuICAgICAgICAgICAgLy8gY29lZmZUb1N0cmluZyB0byB0aHJvdy5cbiAgICAgICAgICAgIGlmICggci5jWzBdICkge1xuICAgICAgICAgICAgICAgIGUgPSByLmU7XG4gICAgICAgICAgICAgICAgcyA9IGUgKyBkcDtcbiAgICAgICAgICAgICAgICBpZiAoIHMgPCAzICkgcyA9IDA7XG5cbiAgICAgICAgICAgICAgICAvLyBOZXd0b24tUmFwaHNvbiBpdGVyYXRpb24uXG4gICAgICAgICAgICAgICAgZm9yICggOyA7ICkge1xuICAgICAgICAgICAgICAgICAgICB0ID0gcjtcbiAgICAgICAgICAgICAgICAgICAgciA9IGhhbGYudGltZXMoIHQucGx1cyggZGl2KCB4LCB0LCBkcCwgMSApICkgKTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoIGNvZWZmVG9TdHJpbmcoIHQuYyAgICkuc2xpY2UoIDAsIHMgKSA9PT0gKCBuID1cbiAgICAgICAgICAgICAgICAgICAgICAgICBjb2VmZlRvU3RyaW5nKCByLmMgKSApLnNsaWNlKCAwLCBzICkgKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFRoZSBleHBvbmVudCBvZiByIG1heSBoZXJlIGJlIG9uZSBsZXNzIHRoYW4gdGhlIGZpbmFsIHJlc3VsdCBleHBvbmVudCxcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGUuZyAwLjAwMDk5OTkgKGUtNCkgLS0+IDAuMDAxIChlLTMpLCBzbyBhZGp1c3QgcyBzbyB0aGUgcm91bmRpbmcgZGlnaXRzXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBhcmUgaW5kZXhlZCBjb3JyZWN0bHkuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIHIuZSA8IGUgKSAtLXM7XG4gICAgICAgICAgICAgICAgICAgICAgICBuID0gbi5zbGljZSggcyAtIDMsIHMgKyAxICk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFRoZSA0dGggcm91bmRpbmcgZGlnaXQgbWF5IGJlIGluIGVycm9yIGJ5IC0xIHNvIGlmIHRoZSA0IHJvdW5kaW5nIGRpZ2l0c1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gYXJlIDk5OTkgb3IgNDk5OSAoaS5lLiBhcHByb2FjaGluZyBhIHJvdW5kaW5nIGJvdW5kYXJ5KSBjb250aW51ZSB0aGVcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGl0ZXJhdGlvbi5cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICggbiA9PSAnOTk5OScgfHwgIXJlcCAmJiBuID09ICc0OTk5JyApIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIE9uIHRoZSBmaXJzdCBpdGVyYXRpb24gb25seSwgY2hlY2sgdG8gc2VlIGlmIHJvdW5kaW5nIHVwIGdpdmVzIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGV4YWN0IHJlc3VsdCBhcyB0aGUgbmluZXMgbWF5IGluZmluaXRlbHkgcmVwZWF0LlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICggIXJlcCApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm91bmQoIHQsIHQuZSArIERFQ0lNQUxfUExBQ0VTICsgMiwgMCApO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICggdC50aW1lcyh0KS5lcSh4KSApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHIgPSB0O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcCArPSA0O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHMgKz0gNDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXAgPSAxO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIHJvdW5kaW5nIGRpZ2l0cyBhcmUgbnVsbCwgMHswLDR9IG9yIDUwezAsM30sIGNoZWNrIGZvciBleGFjdFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHJlc3VsdC4gSWYgbm90LCB0aGVuIHRoZXJlIGFyZSBmdXJ0aGVyIGRpZ2l0cyBhbmQgbSB3aWxsIGJlIHRydXRoeS5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoICErbiB8fCAhK24uc2xpY2UoMSkgJiYgbi5jaGFyQXQoMCkgPT0gJzUnICkge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFRydW5jYXRlIHRvIHRoZSBmaXJzdCByb3VuZGluZyBkaWdpdC5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm91bmQoIHIsIHIuZSArIERFQ0lNQUxfUExBQ0VTICsgMiwgMSApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtID0gIXIudGltZXMocikuZXEoeCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiByb3VuZCggciwgci5lICsgREVDSU1BTF9QTEFDRVMgKyAxLCBST1VORElOR19NT0RFLCBtICk7XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiAgbiAqIDAgPSAwXG4gICAgICAgICAqICBuICogTiA9IE5cbiAgICAgICAgICogIG4gKiBJID0gSVxuICAgICAgICAgKiAgMCAqIG4gPSAwXG4gICAgICAgICAqICAwICogMCA9IDBcbiAgICAgICAgICogIDAgKiBOID0gTlxuICAgICAgICAgKiAgMCAqIEkgPSBOXG4gICAgICAgICAqICBOICogbiA9IE5cbiAgICAgICAgICogIE4gKiAwID0gTlxuICAgICAgICAgKiAgTiAqIE4gPSBOXG4gICAgICAgICAqICBOICogSSA9IE5cbiAgICAgICAgICogIEkgKiBuID0gSVxuICAgICAgICAgKiAgSSAqIDAgPSBOXG4gICAgICAgICAqICBJICogTiA9IE5cbiAgICAgICAgICogIEkgKiBJID0gSVxuICAgICAgICAgKlxuICAgICAgICAgKiBSZXR1cm4gYSBuZXcgQmlnTnVtYmVyIHdob3NlIHZhbHVlIGlzIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlciB0aW1lcyB0aGUgdmFsdWUgb2ZcbiAgICAgICAgICogQmlnTnVtYmVyKHksIGIpLlxuICAgICAgICAgKi9cbiAgICAgICAgUC50aW1lcyA9IFAubXVsID0gZnVuY3Rpb24gKCB5LCBiICkge1xuICAgICAgICAgICAgdmFyIGMsIGUsIGksIGosIGssIG0sIHhjTCwgeGxvLCB4aGksIHljTCwgeWxvLCB5aGksIHpjLFxuICAgICAgICAgICAgICAgIGJhc2UsIHNxcnRCYXNlLFxuICAgICAgICAgICAgICAgIHggPSB0aGlzLFxuICAgICAgICAgICAgICAgIHhjID0geC5jLFxuICAgICAgICAgICAgICAgIHljID0gKCBpZCA9IDE3LCB5ID0gbmV3IEJpZ051bWJlciggeSwgYiApICkuYztcblxuICAgICAgICAgICAgLy8gRWl0aGVyIE5hTiwgwrFJbmZpbml0eSBvciDCsTA/XG4gICAgICAgICAgICBpZiAoICF4YyB8fCAheWMgfHwgIXhjWzBdIHx8ICF5Y1swXSApIHtcblxuICAgICAgICAgICAgICAgIC8vIFJldHVybiBOYU4gaWYgZWl0aGVyIGlzIE5hTiwgb3Igb25lIGlzIDAgYW5kIHRoZSBvdGhlciBpcyBJbmZpbml0eS5cbiAgICAgICAgICAgICAgICBpZiAoICF4LnMgfHwgIXkucyB8fCB4YyAmJiAheGNbMF0gJiYgIXljIHx8IHljICYmICF5Y1swXSAmJiAheGMgKSB7XG4gICAgICAgICAgICAgICAgICAgIHkuYyA9IHkuZSA9IHkucyA9IG51bGw7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgeS5zICo9IHgucztcblxuICAgICAgICAgICAgICAgICAgICAvLyBSZXR1cm4gwrFJbmZpbml0eSBpZiBlaXRoZXIgaXMgwrFJbmZpbml0eS5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCAheGMgfHwgIXljICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgeS5jID0geS5lID0gbnVsbDtcblxuICAgICAgICAgICAgICAgICAgICAvLyBSZXR1cm4gwrEwIGlmIGVpdGhlciBpcyDCsTAuXG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB5LmMgPSBbMF07XG4gICAgICAgICAgICAgICAgICAgICAgICB5LmUgPSAwO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGUgPSBiaXRGbG9vciggeC5lIC8gTE9HX0JBU0UgKSArIGJpdEZsb29yKCB5LmUgLyBMT0dfQkFTRSApO1xuICAgICAgICAgICAgeS5zICo9IHgucztcbiAgICAgICAgICAgIHhjTCA9IHhjLmxlbmd0aDtcbiAgICAgICAgICAgIHljTCA9IHljLmxlbmd0aDtcblxuICAgICAgICAgICAgLy8gRW5zdXJlIHhjIHBvaW50cyB0byBsb25nZXIgYXJyYXkgYW5kIHhjTCB0byBpdHMgbGVuZ3RoLlxuICAgICAgICAgICAgaWYgKCB4Y0wgPCB5Y0wgKSB6YyA9IHhjLCB4YyA9IHljLCB5YyA9IHpjLCBpID0geGNMLCB4Y0wgPSB5Y0wsIHljTCA9IGk7XG5cbiAgICAgICAgICAgIC8vIEluaXRpYWxpc2UgdGhlIHJlc3VsdCBhcnJheSB3aXRoIHplcm9zLlxuICAgICAgICAgICAgZm9yICggaSA9IHhjTCArIHljTCwgemMgPSBbXTsgaS0tOyB6Yy5wdXNoKDApICk7XG5cbiAgICAgICAgICAgIGJhc2UgPSBCQVNFO1xuICAgICAgICAgICAgc3FydEJhc2UgPSBTUVJUX0JBU0U7XG5cbiAgICAgICAgICAgIGZvciAoIGkgPSB5Y0w7IC0taSA+PSAwOyApIHtcbiAgICAgICAgICAgICAgICBjID0gMDtcbiAgICAgICAgICAgICAgICB5bG8gPSB5Y1tpXSAlIHNxcnRCYXNlO1xuICAgICAgICAgICAgICAgIHloaSA9IHljW2ldIC8gc3FydEJhc2UgfCAwO1xuXG4gICAgICAgICAgICAgICAgZm9yICggayA9IHhjTCwgaiA9IGkgKyBrOyBqID4gaTsgKSB7XG4gICAgICAgICAgICAgICAgICAgIHhsbyA9IHhjWy0ta10gJSBzcXJ0QmFzZTtcbiAgICAgICAgICAgICAgICAgICAgeGhpID0geGNba10gLyBzcXJ0QmFzZSB8IDA7XG4gICAgICAgICAgICAgICAgICAgIG0gPSB5aGkgKiB4bG8gKyB4aGkgKiB5bG87XG4gICAgICAgICAgICAgICAgICAgIHhsbyA9IHlsbyAqIHhsbyArICggKCBtICUgc3FydEJhc2UgKSAqIHNxcnRCYXNlICkgKyB6Y1tqXSArIGM7XG4gICAgICAgICAgICAgICAgICAgIGMgPSAoIHhsbyAvIGJhc2UgfCAwICkgKyAoIG0gLyBzcXJ0QmFzZSB8IDAgKSArIHloaSAqIHhoaTtcbiAgICAgICAgICAgICAgICAgICAgemNbai0tXSA9IHhsbyAlIGJhc2U7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgemNbal0gPSBjO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoYykge1xuICAgICAgICAgICAgICAgICsrZTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgemMuc2hpZnQoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIG5vcm1hbGlzZSggeSwgemMsIGUgKTtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiBhIG5ldyBCaWdOdW1iZXIgd2hvc2UgdmFsdWUgaXMgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIHJvdW5kZWQgdG8gYSBtYXhpbXVtIG9mXG4gICAgICAgICAqIHNkIHNpZ25pZmljYW50IGRpZ2l0cyB1c2luZyByb3VuZGluZyBtb2RlIHJtLCBvciBST1VORElOR19NT0RFIGlmIHJtIGlzIG9taXR0ZWQuXG4gICAgICAgICAqXG4gICAgICAgICAqIFtzZF0ge251bWJlcn0gU2lnbmlmaWNhbnQgZGlnaXRzLiBJbnRlZ2VyLCAxIHRvIE1BWCBpbmNsdXNpdmUuXG4gICAgICAgICAqIFtybV0ge251bWJlcn0gUm91bmRpbmcgbW9kZS4gSW50ZWdlciwgMCB0byA4IGluY2x1c2l2ZS5cbiAgICAgICAgICpcbiAgICAgICAgICogJ3RvRGlnaXRzKCkgcHJlY2lzaW9uIG91dCBvZiByYW5nZToge3NkfSdcbiAgICAgICAgICogJ3RvRGlnaXRzKCkgcHJlY2lzaW9uIG5vdCBhbiBpbnRlZ2VyOiB7c2R9J1xuICAgICAgICAgKiAndG9EaWdpdHMoKSByb3VuZGluZyBtb2RlIG5vdCBhbiBpbnRlZ2VyOiB7cm19J1xuICAgICAgICAgKiAndG9EaWdpdHMoKSByb3VuZGluZyBtb2RlIG91dCBvZiByYW5nZToge3JtfSdcbiAgICAgICAgICovXG4gICAgICAgIFAudG9EaWdpdHMgPSBmdW5jdGlvbiAoIHNkLCBybSApIHtcbiAgICAgICAgICAgIHZhciBuID0gbmV3IEJpZ051bWJlcih0aGlzKTtcbiAgICAgICAgICAgIHNkID0gc2QgPT0gbnVsbCB8fCAhaXNWYWxpZEludCggc2QsIDEsIE1BWCwgMTgsICdwcmVjaXNpb24nICkgPyBudWxsIDogc2QgfCAwO1xuICAgICAgICAgICAgcm0gPSBybSA9PSBudWxsIHx8ICFpc1ZhbGlkSW50KCBybSwgMCwgOCwgMTgsIHJvdW5kaW5nTW9kZSApID8gUk9VTkRJTkdfTU9ERSA6IHJtIHwgMDtcbiAgICAgICAgICAgIHJldHVybiBzZCA/IHJvdW5kKCBuLCBzZCwgcm0gKSA6IG47XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gYSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlciBpbiBleHBvbmVudGlhbCBub3RhdGlvbiBhbmRcbiAgICAgICAgICogcm91bmRlZCB1c2luZyBST1VORElOR19NT0RFIHRvIGRwIGZpeGVkIGRlY2ltYWwgcGxhY2VzLlxuICAgICAgICAgKlxuICAgICAgICAgKiBbZHBdIHtudW1iZXJ9IERlY2ltYWwgcGxhY2VzLiBJbnRlZ2VyLCAwIHRvIE1BWCBpbmNsdXNpdmUuXG4gICAgICAgICAqIFtybV0ge251bWJlcn0gUm91bmRpbmcgbW9kZS4gSW50ZWdlciwgMCB0byA4IGluY2x1c2l2ZS5cbiAgICAgICAgICpcbiAgICAgICAgICogJ3RvRXhwb25lbnRpYWwoKSBkZWNpbWFsIHBsYWNlcyBub3QgYW4gaW50ZWdlcjoge2RwfSdcbiAgICAgICAgICogJ3RvRXhwb25lbnRpYWwoKSBkZWNpbWFsIHBsYWNlcyBvdXQgb2YgcmFuZ2U6IHtkcH0nXG4gICAgICAgICAqICd0b0V4cG9uZW50aWFsKCkgcm91bmRpbmcgbW9kZSBub3QgYW4gaW50ZWdlcjoge3JtfSdcbiAgICAgICAgICogJ3RvRXhwb25lbnRpYWwoKSByb3VuZGluZyBtb2RlIG91dCBvZiByYW5nZToge3JtfSdcbiAgICAgICAgICovXG4gICAgICAgIFAudG9FeHBvbmVudGlhbCA9IGZ1bmN0aW9uICggZHAsIHJtICkge1xuICAgICAgICAgICAgcmV0dXJuIGZvcm1hdCggdGhpcyxcbiAgICAgICAgICAgICAgZHAgIT0gbnVsbCAmJiBpc1ZhbGlkSW50KCBkcCwgMCwgTUFYLCAxOSApID8gfn5kcCArIDEgOiBudWxsLCBybSwgMTkgKTtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiBhIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIGluIGZpeGVkLXBvaW50IG5vdGF0aW9uIHJvdW5kaW5nXG4gICAgICAgICAqIHRvIGRwIGZpeGVkIGRlY2ltYWwgcGxhY2VzIHVzaW5nIHJvdW5kaW5nIG1vZGUgcm0sIG9yIFJPVU5ESU5HX01PREUgaWYgcm0gaXMgb21pdHRlZC5cbiAgICAgICAgICpcbiAgICAgICAgICogTm90ZTogYXMgd2l0aCBKYXZhU2NyaXB0J3MgbnVtYmVyIHR5cGUsICgtMCkudG9GaXhlZCgwKSBpcyAnMCcsXG4gICAgICAgICAqIGJ1dCBlLmcuICgtMC4wMDAwMSkudG9GaXhlZCgwKSBpcyAnLTAnLlxuICAgICAgICAgKlxuICAgICAgICAgKiBbZHBdIHtudW1iZXJ9IERlY2ltYWwgcGxhY2VzLiBJbnRlZ2VyLCAwIHRvIE1BWCBpbmNsdXNpdmUuXG4gICAgICAgICAqIFtybV0ge251bWJlcn0gUm91bmRpbmcgbW9kZS4gSW50ZWdlciwgMCB0byA4IGluY2x1c2l2ZS5cbiAgICAgICAgICpcbiAgICAgICAgICogJ3RvRml4ZWQoKSBkZWNpbWFsIHBsYWNlcyBub3QgYW4gaW50ZWdlcjoge2RwfSdcbiAgICAgICAgICogJ3RvRml4ZWQoKSBkZWNpbWFsIHBsYWNlcyBvdXQgb2YgcmFuZ2U6IHtkcH0nXG4gICAgICAgICAqICd0b0ZpeGVkKCkgcm91bmRpbmcgbW9kZSBub3QgYW4gaW50ZWdlcjoge3JtfSdcbiAgICAgICAgICogJ3RvRml4ZWQoKSByb3VuZGluZyBtb2RlIG91dCBvZiByYW5nZToge3JtfSdcbiAgICAgICAgICovXG4gICAgICAgIFAudG9GaXhlZCA9IGZ1bmN0aW9uICggZHAsIHJtICkge1xuICAgICAgICAgICAgcmV0dXJuIGZvcm1hdCggdGhpcywgZHAgIT0gbnVsbCAmJiBpc1ZhbGlkSW50KCBkcCwgMCwgTUFYLCAyMCApXG4gICAgICAgICAgICAgID8gfn5kcCArIHRoaXMuZSArIDEgOiBudWxsLCBybSwgMjAgKTtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiBhIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIGluIGZpeGVkLXBvaW50IG5vdGF0aW9uIHJvdW5kZWRcbiAgICAgICAgICogdXNpbmcgcm0gb3IgUk9VTkRJTkdfTU9ERSB0byBkcCBkZWNpbWFsIHBsYWNlcywgYW5kIGZvcm1hdHRlZCBhY2NvcmRpbmcgdG8gdGhlIHByb3BlcnRpZXNcbiAgICAgICAgICogb2YgdGhlIEZPUk1BVCBvYmplY3QgKHNlZSBCaWdOdW1iZXIuY29uZmlnKS5cbiAgICAgICAgICpcbiAgICAgICAgICogRk9STUFUID0ge1xuICAgICAgICAgKiAgICAgIGRlY2ltYWxTZXBhcmF0b3IgOiAnLicsXG4gICAgICAgICAqICAgICAgZ3JvdXBTZXBhcmF0b3IgOiAnLCcsXG4gICAgICAgICAqICAgICAgZ3JvdXBTaXplIDogMyxcbiAgICAgICAgICogICAgICBzZWNvbmRhcnlHcm91cFNpemUgOiAwLFxuICAgICAgICAgKiAgICAgIGZyYWN0aW9uR3JvdXBTZXBhcmF0b3IgOiAnXFx4QTAnLCAgICAvLyBub24tYnJlYWtpbmcgc3BhY2VcbiAgICAgICAgICogICAgICBmcmFjdGlvbkdyb3VwU2l6ZSA6IDBcbiAgICAgICAgICogfTtcbiAgICAgICAgICpcbiAgICAgICAgICogW2RwXSB7bnVtYmVyfSBEZWNpbWFsIHBsYWNlcy4gSW50ZWdlciwgMCB0byBNQVggaW5jbHVzaXZlLlxuICAgICAgICAgKiBbcm1dIHtudW1iZXJ9IFJvdW5kaW5nIG1vZGUuIEludGVnZXIsIDAgdG8gOCBpbmNsdXNpdmUuXG4gICAgICAgICAqXG4gICAgICAgICAqICd0b0Zvcm1hdCgpIGRlY2ltYWwgcGxhY2VzIG5vdCBhbiBpbnRlZ2VyOiB7ZHB9J1xuICAgICAgICAgKiAndG9Gb3JtYXQoKSBkZWNpbWFsIHBsYWNlcyBvdXQgb2YgcmFuZ2U6IHtkcH0nXG4gICAgICAgICAqICd0b0Zvcm1hdCgpIHJvdW5kaW5nIG1vZGUgbm90IGFuIGludGVnZXI6IHtybX0nXG4gICAgICAgICAqICd0b0Zvcm1hdCgpIHJvdW5kaW5nIG1vZGUgb3V0IG9mIHJhbmdlOiB7cm19J1xuICAgICAgICAgKi9cbiAgICAgICAgUC50b0Zvcm1hdCA9IGZ1bmN0aW9uICggZHAsIHJtICkge1xuICAgICAgICAgICAgdmFyIHN0ciA9IGZvcm1hdCggdGhpcywgZHAgIT0gbnVsbCAmJiBpc1ZhbGlkSW50KCBkcCwgMCwgTUFYLCAyMSApXG4gICAgICAgICAgICAgID8gfn5kcCArIHRoaXMuZSArIDEgOiBudWxsLCBybSwgMjEgKTtcblxuICAgICAgICAgICAgaWYgKCB0aGlzLmMgKSB7XG4gICAgICAgICAgICAgICAgdmFyIGksXG4gICAgICAgICAgICAgICAgICAgIGFyciA9IHN0ci5zcGxpdCgnLicpLFxuICAgICAgICAgICAgICAgICAgICBnMSA9ICtGT1JNQVQuZ3JvdXBTaXplLFxuICAgICAgICAgICAgICAgICAgICBnMiA9ICtGT1JNQVQuc2Vjb25kYXJ5R3JvdXBTaXplLFxuICAgICAgICAgICAgICAgICAgICBncm91cFNlcGFyYXRvciA9IEZPUk1BVC5ncm91cFNlcGFyYXRvcixcbiAgICAgICAgICAgICAgICAgICAgaW50UGFydCA9IGFyclswXSxcbiAgICAgICAgICAgICAgICAgICAgZnJhY3Rpb25QYXJ0ID0gYXJyWzFdLFxuICAgICAgICAgICAgICAgICAgICBpc05lZyA9IHRoaXMucyA8IDAsXG4gICAgICAgICAgICAgICAgICAgIGludERpZ2l0cyA9IGlzTmVnID8gaW50UGFydC5zbGljZSgxKSA6IGludFBhcnQsXG4gICAgICAgICAgICAgICAgICAgIGxlbiA9IGludERpZ2l0cy5sZW5ndGg7XG5cbiAgICAgICAgICAgICAgICBpZiAoZzIpIGkgPSBnMSwgZzEgPSBnMiwgZzIgPSBpLCBsZW4gLT0gaTtcblxuICAgICAgICAgICAgICAgIGlmICggZzEgPiAwICYmIGxlbiA+IDAgKSB7XG4gICAgICAgICAgICAgICAgICAgIGkgPSBsZW4gJSBnMSB8fCBnMTtcbiAgICAgICAgICAgICAgICAgICAgaW50UGFydCA9IGludERpZ2l0cy5zdWJzdHIoIDAsIGkgKTtcblxuICAgICAgICAgICAgICAgICAgICBmb3IgKCA7IGkgPCBsZW47IGkgKz0gZzEgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpbnRQYXJ0ICs9IGdyb3VwU2VwYXJhdG9yICsgaW50RGlnaXRzLnN1YnN0ciggaSwgZzEgKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGlmICggZzIgPiAwICkgaW50UGFydCArPSBncm91cFNlcGFyYXRvciArIGludERpZ2l0cy5zbGljZShpKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGlzTmVnKSBpbnRQYXJ0ID0gJy0nICsgaW50UGFydDtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBzdHIgPSBmcmFjdGlvblBhcnRcbiAgICAgICAgICAgICAgICAgID8gaW50UGFydCArIEZPUk1BVC5kZWNpbWFsU2VwYXJhdG9yICsgKCAoIGcyID0gK0ZPUk1BVC5mcmFjdGlvbkdyb3VwU2l6ZSApXG4gICAgICAgICAgICAgICAgICAgID8gZnJhY3Rpb25QYXJ0LnJlcGxhY2UoIG5ldyBSZWdFeHAoICdcXFxcZHsnICsgZzIgKyAnfVxcXFxCJywgJ2cnICksXG4gICAgICAgICAgICAgICAgICAgICAgJyQmJyArIEZPUk1BVC5mcmFjdGlvbkdyb3VwU2VwYXJhdG9yIClcbiAgICAgICAgICAgICAgICAgICAgOiBmcmFjdGlvblBhcnQgKVxuICAgICAgICAgICAgICAgICAgOiBpbnRQYXJ0O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gc3RyO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIGEgc3RyaW5nIGFycmF5IHJlcHJlc2VudGluZyB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgYXMgYSBzaW1wbGUgZnJhY3Rpb24gd2l0aFxuICAgICAgICAgKiBhbiBpbnRlZ2VyIG51bWVyYXRvciBhbmQgYW4gaW50ZWdlciBkZW5vbWluYXRvci4gVGhlIGRlbm9taW5hdG9yIHdpbGwgYmUgYSBwb3NpdGl2ZVxuICAgICAgICAgKiBub24temVybyB2YWx1ZSBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gdGhlIHNwZWNpZmllZCBtYXhpbXVtIGRlbm9taW5hdG9yLiBJZiBhIG1heGltdW1cbiAgICAgICAgICogZGVub21pbmF0b3IgaXMgbm90IHNwZWNpZmllZCwgdGhlIGRlbm9taW5hdG9yIHdpbGwgYmUgdGhlIGxvd2VzdCB2YWx1ZSBuZWNlc3NhcnkgdG9cbiAgICAgICAgICogcmVwcmVzZW50IHRoZSBudW1iZXIgZXhhY3RseS5cbiAgICAgICAgICpcbiAgICAgICAgICogW21kXSB7bnVtYmVyfHN0cmluZ3xCaWdOdW1iZXJ9IEludGVnZXIgPj0gMSBhbmQgPCBJbmZpbml0eS4gVGhlIG1heGltdW0gZGVub21pbmF0b3IuXG4gICAgICAgICAqXG4gICAgICAgICAqICd0b0ZyYWN0aW9uKCkgbWF4IGRlbm9taW5hdG9yIG5vdCBhbiBpbnRlZ2VyOiB7bWR9J1xuICAgICAgICAgKiAndG9GcmFjdGlvbigpIG1heCBkZW5vbWluYXRvciBvdXQgb2YgcmFuZ2U6IHttZH0nXG4gICAgICAgICAqL1xuICAgICAgICBQLnRvRnJhY3Rpb24gPSBmdW5jdGlvbiAobWQpIHtcbiAgICAgICAgICAgIHZhciBhcnIsIGQwLCBkMiwgZSwgZXhwLCBuLCBuMCwgcSwgcyxcbiAgICAgICAgICAgICAgICBrID0gRVJST1JTLFxuICAgICAgICAgICAgICAgIHggPSB0aGlzLFxuICAgICAgICAgICAgICAgIHhjID0geC5jLFxuICAgICAgICAgICAgICAgIGQgPSBuZXcgQmlnTnVtYmVyKE9ORSksXG4gICAgICAgICAgICAgICAgbjEgPSBkMCA9IG5ldyBCaWdOdW1iZXIoT05FKSxcbiAgICAgICAgICAgICAgICBkMSA9IG4wID0gbmV3IEJpZ051bWJlcihPTkUpO1xuXG4gICAgICAgICAgICBpZiAoIG1kICE9IG51bGwgKSB7XG4gICAgICAgICAgICAgICAgRVJST1JTID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgbiA9IG5ldyBCaWdOdW1iZXIobWQpO1xuICAgICAgICAgICAgICAgIEVSUk9SUyA9IGs7XG5cbiAgICAgICAgICAgICAgICBpZiAoICEoIGsgPSBuLmlzSW50KCkgKSB8fCBuLmx0KE9ORSkgKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKEVSUk9SUykge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmFpc2UoIDIyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAnbWF4IGRlbm9taW5hdG9yICcgKyAoIGsgPyAnb3V0IG9mIHJhbmdlJyA6ICdub3QgYW4gaW50ZWdlcicgKSwgbWQgKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIEVSUk9SUyBpcyBmYWxzZTpcbiAgICAgICAgICAgICAgICAgICAgLy8gSWYgbWQgaXMgYSBmaW5pdGUgbm9uLWludGVnZXIgPj0gMSwgcm91bmQgaXQgdG8gYW4gaW50ZWdlciBhbmQgdXNlIGl0LlxuICAgICAgICAgICAgICAgICAgICBtZCA9ICFrICYmIG4uYyAmJiByb3VuZCggbiwgbi5lICsgMSwgMSApLmd0ZShPTkUpID8gbiA6IG51bGw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoICF4YyApIHJldHVybiB4LnRvU3RyaW5nKCk7XG4gICAgICAgICAgICBzID0gY29lZmZUb1N0cmluZyh4Yyk7XG5cbiAgICAgICAgICAgIC8vIERldGVybWluZSBpbml0aWFsIGRlbm9taW5hdG9yLlxuICAgICAgICAgICAgLy8gZCBpcyBhIHBvd2VyIG9mIDEwIGFuZCB0aGUgbWluaW11bSBtYXggZGVub21pbmF0b3IgdGhhdCBzcGVjaWZpZXMgdGhlIHZhbHVlIGV4YWN0bHkuXG4gICAgICAgICAgICBlID0gZC5lID0gcy5sZW5ndGggLSB4LmUgLSAxO1xuICAgICAgICAgICAgZC5jWzBdID0gUE9XU19URU5bICggZXhwID0gZSAlIExPR19CQVNFICkgPCAwID8gTE9HX0JBU0UgKyBleHAgOiBleHAgXTtcbiAgICAgICAgICAgIG1kID0gIW1kIHx8IG4uY21wKGQpID4gMCA/ICggZSA+IDAgPyBkIDogbjEgKSA6IG47XG5cbiAgICAgICAgICAgIGV4cCA9IE1BWF9FWFA7XG4gICAgICAgICAgICBNQVhfRVhQID0gMSAvIDA7XG4gICAgICAgICAgICBuID0gbmV3IEJpZ051bWJlcihzKTtcblxuICAgICAgICAgICAgLy8gbjAgPSBkMSA9IDBcbiAgICAgICAgICAgIG4wLmNbMF0gPSAwO1xuXG4gICAgICAgICAgICBmb3IgKCA7IDsgKSAge1xuICAgICAgICAgICAgICAgIHEgPSBkaXYoIG4sIGQsIDAsIDEgKTtcbiAgICAgICAgICAgICAgICBkMiA9IGQwLnBsdXMoIHEudGltZXMoZDEpICk7XG4gICAgICAgICAgICAgICAgaWYgKCBkMi5jbXAobWQpID09IDEgKSBicmVhaztcbiAgICAgICAgICAgICAgICBkMCA9IGQxO1xuICAgICAgICAgICAgICAgIGQxID0gZDI7XG4gICAgICAgICAgICAgICAgbjEgPSBuMC5wbHVzKCBxLnRpbWVzKCBkMiA9IG4xICkgKTtcbiAgICAgICAgICAgICAgICBuMCA9IGQyO1xuICAgICAgICAgICAgICAgIGQgPSBuLm1pbnVzKCBxLnRpbWVzKCBkMiA9IGQgKSApO1xuICAgICAgICAgICAgICAgIG4gPSBkMjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZDIgPSBkaXYoIG1kLm1pbnVzKGQwKSwgZDEsIDAsIDEgKTtcbiAgICAgICAgICAgIG4wID0gbjAucGx1cyggZDIudGltZXMobjEpICk7XG4gICAgICAgICAgICBkMCA9IGQwLnBsdXMoIGQyLnRpbWVzKGQxKSApO1xuICAgICAgICAgICAgbjAucyA9IG4xLnMgPSB4LnM7XG4gICAgICAgICAgICBlICo9IDI7XG5cbiAgICAgICAgICAgIC8vIERldGVybWluZSB3aGljaCBmcmFjdGlvbiBpcyBjbG9zZXIgdG8geCwgbjAvZDAgb3IgbjEvZDFcbiAgICAgICAgICAgIGFyciA9IGRpdiggbjEsIGQxLCBlLCBST1VORElOR19NT0RFICkubWludXMoeCkuYWJzKCkuY21wKFxuICAgICAgICAgICAgICAgICAgZGl2KCBuMCwgZDAsIGUsIFJPVU5ESU5HX01PREUgKS5taW51cyh4KS5hYnMoKSApIDwgMVxuICAgICAgICAgICAgICAgICAgICA/IFsgbjEudG9TdHJpbmcoKSwgZDEudG9TdHJpbmcoKSBdXG4gICAgICAgICAgICAgICAgICAgIDogWyBuMC50b1N0cmluZygpLCBkMC50b1N0cmluZygpIF07XG5cbiAgICAgICAgICAgIE1BWF9FWFAgPSBleHA7XG4gICAgICAgICAgICByZXR1cm4gYXJyO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlciBjb252ZXJ0ZWQgdG8gYSBudW1iZXIgcHJpbWl0aXZlLlxuICAgICAgICAgKi9cbiAgICAgICAgUC50b051bWJlciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciB4ID0gdGhpcztcblxuICAgICAgICAgICAgLy8gRW5zdXJlIHplcm8gaGFzIGNvcnJlY3Qgc2lnbi5cbiAgICAgICAgICAgIHJldHVybiAreCB8fCAoIHgucyA/IHgucyAqIDAgOiBOYU4gKTtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiBhIEJpZ051bWJlciB3aG9zZSB2YWx1ZSBpcyB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgcmFpc2VkIHRvIHRoZSBwb3dlciBuLlxuICAgICAgICAgKiBJZiBuIGlzIG5lZ2F0aXZlIHJvdW5kIGFjY29yZGluZyB0byBERUNJTUFMX1BMQUNFUyBhbmQgUk9VTkRJTkdfTU9ERS5cbiAgICAgICAgICogSWYgUE9XX1BSRUNJU0lPTiBpcyBub3QgMCwgcm91bmQgdG8gUE9XX1BSRUNJU0lPTiB1c2luZyBST1VORElOR19NT0RFLlxuICAgICAgICAgKlxuICAgICAgICAgKiBuIHtudW1iZXJ9IEludGVnZXIsIC05MDA3MTk5MjU0NzQwOTkyIHRvIDkwMDcxOTkyNTQ3NDA5OTIgaW5jbHVzaXZlLlxuICAgICAgICAgKiAoUGVyZm9ybXMgNTQgbG9vcCBpdGVyYXRpb25zIGZvciBuIG9mIDkwMDcxOTkyNTQ3NDA5OTIuKVxuICAgICAgICAgKlxuICAgICAgICAgKiAncG93KCkgZXhwb25lbnQgbm90IGFuIGludGVnZXI6IHtufSdcbiAgICAgICAgICogJ3BvdygpIGV4cG9uZW50IG91dCBvZiByYW5nZToge259J1xuICAgICAgICAgKi9cbiAgICAgICAgUC50b1Bvd2VyID0gUC5wb3cgPSBmdW5jdGlvbiAobikge1xuICAgICAgICAgICAgdmFyIGssIHksXG4gICAgICAgICAgICAgICAgaSA9IG1hdGhmbG9vciggbiA8IDAgPyAtbiA6ICtuICksXG4gICAgICAgICAgICAgICAgeCA9IHRoaXM7XG5cbiAgICAgICAgICAgIC8vIFBhc3MgwrFJbmZpbml0eSB0byBNYXRoLnBvdyBpZiBleHBvbmVudCBpcyBvdXQgb2YgcmFuZ2UuXG4gICAgICAgICAgICBpZiAoICFpc1ZhbGlkSW50KCBuLCAtTUFYX1NBRkVfSU5URUdFUiwgTUFYX1NBRkVfSU5URUdFUiwgMjMsICdleHBvbmVudCcgKSAmJlxuICAgICAgICAgICAgICAoICFpc0Zpbml0ZShuKSB8fCBpID4gTUFYX1NBRkVfSU5URUdFUiAmJiAoIG4gLz0gMCApIHx8XG4gICAgICAgICAgICAgICAgcGFyc2VGbG9hdChuKSAhPSBuICYmICEoIG4gPSBOYU4gKSApICkge1xuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgQmlnTnVtYmVyKCBNYXRoLnBvdyggK3gsIG4gKSApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBUcnVuY2F0aW5nIGVhY2ggY29lZmZpY2llbnQgYXJyYXkgdG8gYSBsZW5ndGggb2YgayBhZnRlciBlYWNoIG11bHRpcGxpY2F0aW9uIGVxdWF0ZXNcbiAgICAgICAgICAgIC8vIHRvIHRydW5jYXRpbmcgc2lnbmlmaWNhbnQgZGlnaXRzIHRvIFBPV19QUkVDSVNJT04gKyBbMjgsIDQxXSwgaS5lLiB0aGVyZSB3aWxsIGJlIGFcbiAgICAgICAgICAgIC8vIG1pbmltdW0gb2YgMjggZ3VhcmQgZGlnaXRzIHJldGFpbmVkLiAoVXNpbmcgKyAxLjUgd291bGQgZ2l2ZSBbOSwgMjFdIGd1YXJkIGRpZ2l0cy4pXG4gICAgICAgICAgICBrID0gUE9XX1BSRUNJU0lPTiA/IG1hdGhjZWlsKCBQT1dfUFJFQ0lTSU9OIC8gTE9HX0JBU0UgKyAyICkgOiAwO1xuICAgICAgICAgICAgeSA9IG5ldyBCaWdOdW1iZXIoT05FKTtcblxuICAgICAgICAgICAgZm9yICggOyA7ICkge1xuXG4gICAgICAgICAgICAgICAgaWYgKCBpICUgMiApIHtcbiAgICAgICAgICAgICAgICAgICAgeSA9IHkudGltZXMoeCk7XG4gICAgICAgICAgICAgICAgICAgIGlmICggIXkuYyApIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICBpZiAoIGsgJiYgeS5jLmxlbmd0aCA+IGsgKSB5LmMubGVuZ3RoID0gaztcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpID0gbWF0aGZsb29yKCBpIC8gMiApO1xuICAgICAgICAgICAgICAgIGlmICggIWkgKSBicmVhaztcblxuICAgICAgICAgICAgICAgIHggPSB4LnRpbWVzKHgpO1xuICAgICAgICAgICAgICAgIGlmICggayAmJiB4LmMgJiYgeC5jLmxlbmd0aCA+IGsgKSB4LmMubGVuZ3RoID0gaztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCBuIDwgMCApIHkgPSBPTkUuZGl2KHkpO1xuICAgICAgICAgICAgcmV0dXJuIGsgPyByb3VuZCggeSwgUE9XX1BSRUNJU0lPTiwgUk9VTkRJTkdfTU9ERSApIDogeTtcbiAgICAgICAgfTtcblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiBhIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIHZhbHVlIG9mIHRoaXMgQmlnTnVtYmVyIHJvdW5kZWQgdG8gc2Qgc2lnbmlmaWNhbnQgZGlnaXRzXG4gICAgICAgICAqIHVzaW5nIHJvdW5kaW5nIG1vZGUgcm0gb3IgUk9VTkRJTkdfTU9ERS4gSWYgc2QgaXMgbGVzcyB0aGFuIHRoZSBudW1iZXIgb2YgZGlnaXRzXG4gICAgICAgICAqIG5lY2Vzc2FyeSB0byByZXByZXNlbnQgdGhlIGludGVnZXIgcGFydCBvZiB0aGUgdmFsdWUgaW4gZml4ZWQtcG9pbnQgbm90YXRpb24sIHRoZW4gdXNlXG4gICAgICAgICAqIGV4cG9uZW50aWFsIG5vdGF0aW9uLlxuICAgICAgICAgKlxuICAgICAgICAgKiBbc2RdIHtudW1iZXJ9IFNpZ25pZmljYW50IGRpZ2l0cy4gSW50ZWdlciwgMSB0byBNQVggaW5jbHVzaXZlLlxuICAgICAgICAgKiBbcm1dIHtudW1iZXJ9IFJvdW5kaW5nIG1vZGUuIEludGVnZXIsIDAgdG8gOCBpbmNsdXNpdmUuXG4gICAgICAgICAqXG4gICAgICAgICAqICd0b1ByZWNpc2lvbigpIHByZWNpc2lvbiBub3QgYW4gaW50ZWdlcjoge3NkfSdcbiAgICAgICAgICogJ3RvUHJlY2lzaW9uKCkgcHJlY2lzaW9uIG91dCBvZiByYW5nZToge3NkfSdcbiAgICAgICAgICogJ3RvUHJlY2lzaW9uKCkgcm91bmRpbmcgbW9kZSBub3QgYW4gaW50ZWdlcjoge3JtfSdcbiAgICAgICAgICogJ3RvUHJlY2lzaW9uKCkgcm91bmRpbmcgbW9kZSBvdXQgb2YgcmFuZ2U6IHtybX0nXG4gICAgICAgICAqL1xuICAgICAgICBQLnRvUHJlY2lzaW9uID0gZnVuY3Rpb24gKCBzZCwgcm0gKSB7XG4gICAgICAgICAgICByZXR1cm4gZm9ybWF0KCB0aGlzLCBzZCAhPSBudWxsICYmIGlzVmFsaWRJbnQoIHNkLCAxLCBNQVgsIDI0LCAncHJlY2lzaW9uJyApXG4gICAgICAgICAgICAgID8gc2QgfCAwIDogbnVsbCwgcm0sIDI0ICk7XG4gICAgICAgIH07XG5cblxuICAgICAgICAvKlxuICAgICAgICAgKiBSZXR1cm4gYSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSB2YWx1ZSBvZiB0aGlzIEJpZ051bWJlciBpbiBiYXNlIGIsIG9yIGJhc2UgMTAgaWYgYiBpc1xuICAgICAgICAgKiBvbWl0dGVkLiBJZiBhIGJhc2UgaXMgc3BlY2lmaWVkLCBpbmNsdWRpbmcgYmFzZSAxMCwgcm91bmQgYWNjb3JkaW5nIHRvIERFQ0lNQUxfUExBQ0VTIGFuZFxuICAgICAgICAgKiBST1VORElOR19NT0RFLiBJZiBhIGJhc2UgaXMgbm90IHNwZWNpZmllZCwgYW5kIHRoaXMgQmlnTnVtYmVyIGhhcyBhIHBvc2l0aXZlIGV4cG9uZW50XG4gICAgICAgICAqIHRoYXQgaXMgZXF1YWwgdG8gb3IgZ3JlYXRlciB0aGFuIFRPX0VYUF9QT1MsIG9yIGEgbmVnYXRpdmUgZXhwb25lbnQgZXF1YWwgdG8gb3IgbGVzcyB0aGFuXG4gICAgICAgICAqIFRPX0VYUF9ORUcsIHJldHVybiBleHBvbmVudGlhbCBub3RhdGlvbi5cbiAgICAgICAgICpcbiAgICAgICAgICogW2JdIHtudW1iZXJ9IEludGVnZXIsIDIgdG8gNjQgaW5jbHVzaXZlLlxuICAgICAgICAgKlxuICAgICAgICAgKiAndG9TdHJpbmcoKSBiYXNlIG5vdCBhbiBpbnRlZ2VyOiB7Yn0nXG4gICAgICAgICAqICd0b1N0cmluZygpIGJhc2Ugb3V0IG9mIHJhbmdlOiB7Yn0nXG4gICAgICAgICAqL1xuICAgICAgICBQLnRvU3RyaW5nID0gZnVuY3Rpb24gKGIpIHtcbiAgICAgICAgICAgIHZhciBzdHIsXG4gICAgICAgICAgICAgICAgbiA9IHRoaXMsXG4gICAgICAgICAgICAgICAgcyA9IG4ucyxcbiAgICAgICAgICAgICAgICBlID0gbi5lO1xuXG4gICAgICAgICAgICAvLyBJbmZpbml0eSBvciBOYU4/XG4gICAgICAgICAgICBpZiAoIGUgPT09IG51bGwgKSB7XG5cbiAgICAgICAgICAgICAgICBpZiAocykge1xuICAgICAgICAgICAgICAgICAgICBzdHIgPSAnSW5maW5pdHknO1xuICAgICAgICAgICAgICAgICAgICBpZiAoIHMgPCAwICkgc3RyID0gJy0nICsgc3RyO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHN0ciA9ICdOYU4nO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc3RyID0gY29lZmZUb1N0cmluZyggbi5jICk7XG5cbiAgICAgICAgICAgICAgICBpZiAoIGIgPT0gbnVsbCB8fCAhaXNWYWxpZEludCggYiwgMiwgNjQsIDI1LCAnYmFzZScgKSApIHtcbiAgICAgICAgICAgICAgICAgICAgc3RyID0gZSA8PSBUT19FWFBfTkVHIHx8IGUgPj0gVE9fRVhQX1BPU1xuICAgICAgICAgICAgICAgICAgICAgID8gdG9FeHBvbmVudGlhbCggc3RyLCBlIClcbiAgICAgICAgICAgICAgICAgICAgICA6IHRvRml4ZWRQb2ludCggc3RyLCBlICk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgc3RyID0gY29udmVydEJhc2UoIHRvRml4ZWRQb2ludCggc3RyLCBlICksIGIgfCAwLCAxMCwgcyApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICggcyA8IDAgJiYgbi5jWzBdICkgc3RyID0gJy0nICsgc3RyO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gc3RyO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLypcbiAgICAgICAgICogUmV0dXJuIGEgbmV3IEJpZ051bWJlciB3aG9zZSB2YWx1ZSBpcyB0aGUgdmFsdWUgb2YgdGhpcyBCaWdOdW1iZXIgdHJ1bmNhdGVkIHRvIGEgd2hvbGVcbiAgICAgICAgICogbnVtYmVyLlxuICAgICAgICAgKi9cbiAgICAgICAgUC50cnVuY2F0ZWQgPSBQLnRydW5jID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHJvdW5kKCBuZXcgQmlnTnVtYmVyKHRoaXMpLCB0aGlzLmUgKyAxLCAxICk7XG4gICAgICAgIH07XG5cblxuXG4gICAgICAgIC8qXG4gICAgICAgICAqIFJldHVybiBhcyB0b1N0cmluZywgYnV0IGRvIG5vdCBhY2NlcHQgYSBiYXNlIGFyZ3VtZW50LlxuICAgICAgICAgKi9cbiAgICAgICAgUC52YWx1ZU9mID0gUC50b0pTT04gPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy50b1N0cmluZygpO1xuICAgICAgICB9O1xuXG5cbiAgICAgICAgLy8gQWxpYXNlcyBmb3IgQmlnRGVjaW1hbCBtZXRob2RzLlxuICAgICAgICAvL1AuYWRkID0gUC5wbHVzOyAgICAgICAgIC8vIFAuYWRkIGluY2x1ZGVkIGFib3ZlXG4gICAgICAgIC8vUC5zdWJ0cmFjdCA9IFAubWludXM7ICAgLy8gUC5zdWIgaW5jbHVkZWQgYWJvdmVcbiAgICAgICAgLy9QLm11bHRpcGx5ID0gUC50aW1lczsgICAvLyBQLm11bCBpbmNsdWRlZCBhYm92ZVxuICAgICAgICAvL1AuZGl2aWRlID0gUC5kaXY7XG4gICAgICAgIC8vUC5yZW1haW5kZXIgPSBQLm1vZDtcbiAgICAgICAgLy9QLmNvbXBhcmVUbyA9IFAuY21wO1xuICAgICAgICAvL1AubmVnYXRlID0gUC5uZWc7XG5cblxuICAgICAgICBpZiAoIGNvbmZpZ09iaiAhPSBudWxsICkgQmlnTnVtYmVyLmNvbmZpZyhjb25maWdPYmopO1xuXG4gICAgICAgIHJldHVybiBCaWdOdW1iZXI7XG4gICAgfVxuXG5cbiAgICAvLyBQUklWQVRFIEhFTFBFUiBGVU5DVElPTlNcblxuXG4gICAgZnVuY3Rpb24gYml0Rmxvb3Iobikge1xuICAgICAgICB2YXIgaSA9IG4gfCAwO1xuICAgICAgICByZXR1cm4gbiA+IDAgfHwgbiA9PT0gaSA/IGkgOiBpIC0gMTtcbiAgICB9XG5cblxuICAgIC8vIFJldHVybiBhIGNvZWZmaWNpZW50IGFycmF5IGFzIGEgc3RyaW5nIG9mIGJhc2UgMTAgZGlnaXRzLlxuICAgIGZ1bmN0aW9uIGNvZWZmVG9TdHJpbmcoYSkge1xuICAgICAgICB2YXIgcywgeixcbiAgICAgICAgICAgIGkgPSAxLFxuICAgICAgICAgICAgaiA9IGEubGVuZ3RoLFxuICAgICAgICAgICAgciA9IGFbMF0gKyAnJztcblxuICAgICAgICBmb3IgKCA7IGkgPCBqOyApIHtcbiAgICAgICAgICAgIHMgPSBhW2krK10gKyAnJztcbiAgICAgICAgICAgIHogPSBMT0dfQkFTRSAtIHMubGVuZ3RoO1xuICAgICAgICAgICAgZm9yICggOyB6LS07IHMgPSAnMCcgKyBzICk7XG4gICAgICAgICAgICByICs9IHM7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBEZXRlcm1pbmUgdHJhaWxpbmcgemVyb3MuXG4gICAgICAgIGZvciAoIGogPSByLmxlbmd0aDsgci5jaGFyQ29kZUF0KC0taikgPT09IDQ4OyApO1xuICAgICAgICByZXR1cm4gci5zbGljZSggMCwgaiArIDEgfHwgMSApO1xuICAgIH1cblxuXG4gICAgLy8gQ29tcGFyZSB0aGUgdmFsdWUgb2YgQmlnTnVtYmVycyB4IGFuZCB5LlxuICAgIGZ1bmN0aW9uIGNvbXBhcmUoIHgsIHkgKSB7XG4gICAgICAgIHZhciBhLCBiLFxuICAgICAgICAgICAgeGMgPSB4LmMsXG4gICAgICAgICAgICB5YyA9IHkuYyxcbiAgICAgICAgICAgIGkgPSB4LnMsXG4gICAgICAgICAgICBqID0geS5zLFxuICAgICAgICAgICAgayA9IHguZSxcbiAgICAgICAgICAgIGwgPSB5LmU7XG5cbiAgICAgICAgLy8gRWl0aGVyIE5hTj9cbiAgICAgICAgaWYgKCAhaSB8fCAhaiApIHJldHVybiBudWxsO1xuXG4gICAgICAgIGEgPSB4YyAmJiAheGNbMF07XG4gICAgICAgIGIgPSB5YyAmJiAheWNbMF07XG5cbiAgICAgICAgLy8gRWl0aGVyIHplcm8/XG4gICAgICAgIGlmICggYSB8fCBiICkgcmV0dXJuIGEgPyBiID8gMCA6IC1qIDogaTtcblxuICAgICAgICAvLyBTaWducyBkaWZmZXI/XG4gICAgICAgIGlmICggaSAhPSBqICkgcmV0dXJuIGk7XG5cbiAgICAgICAgYSA9IGkgPCAwO1xuICAgICAgICBiID0gayA9PSBsO1xuXG4gICAgICAgIC8vIEVpdGhlciBJbmZpbml0eT9cbiAgICAgICAgaWYgKCAheGMgfHwgIXljICkgcmV0dXJuIGIgPyAwIDogIXhjIF4gYSA/IDEgOiAtMTtcblxuICAgICAgICAvLyBDb21wYXJlIGV4cG9uZW50cy5cbiAgICAgICAgaWYgKCAhYiApIHJldHVybiBrID4gbCBeIGEgPyAxIDogLTE7XG5cbiAgICAgICAgaiA9ICggayA9IHhjLmxlbmd0aCApIDwgKCBsID0geWMubGVuZ3RoICkgPyBrIDogbDtcblxuICAgICAgICAvLyBDb21wYXJlIGRpZ2l0IGJ5IGRpZ2l0LlxuICAgICAgICBmb3IgKCBpID0gMDsgaSA8IGo7IGkrKyApIGlmICggeGNbaV0gIT0geWNbaV0gKSByZXR1cm4geGNbaV0gPiB5Y1tpXSBeIGEgPyAxIDogLTE7XG5cbiAgICAgICAgLy8gQ29tcGFyZSBsZW5ndGhzLlxuICAgICAgICByZXR1cm4gayA9PSBsID8gMCA6IGsgPiBsIF4gYSA/IDEgOiAtMTtcbiAgICB9XG5cblxuICAgIC8qXG4gICAgICogUmV0dXJuIHRydWUgaWYgbiBpcyBhIHZhbGlkIG51bWJlciBpbiByYW5nZSwgb3RoZXJ3aXNlIGZhbHNlLlxuICAgICAqIFVzZSBmb3IgYXJndW1lbnQgdmFsaWRhdGlvbiB3aGVuIEVSUk9SUyBpcyBmYWxzZS5cbiAgICAgKiBOb3RlOiBwYXJzZUludCgnMWUrMScpID09IDEgYnV0IHBhcnNlRmxvYXQoJzFlKzEnKSA9PSAxMC5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpbnRWYWxpZGF0b3JOb0Vycm9ycyggbiwgbWluLCBtYXggKSB7XG4gICAgICAgIHJldHVybiAoIG4gPSB0cnVuY2F0ZShuKSApID49IG1pbiAmJiBuIDw9IG1heDtcbiAgICB9XG5cblxuICAgIGZ1bmN0aW9uIGlzQXJyYXkob2JqKSB7XG4gICAgICAgIHJldHVybiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwob2JqKSA9PSAnW29iamVjdCBBcnJheV0nO1xuICAgIH1cblxuXG4gICAgLypcbiAgICAgKiBDb252ZXJ0IHN0cmluZyBvZiBiYXNlSW4gdG8gYW4gYXJyYXkgb2YgbnVtYmVycyBvZiBiYXNlT3V0LlxuICAgICAqIEVnLiBjb252ZXJ0QmFzZSgnMjU1JywgMTAsIDE2KSByZXR1cm5zIFsxNSwgMTVdLlxuICAgICAqIEVnLiBjb252ZXJ0QmFzZSgnZmYnLCAxNiwgMTApIHJldHVybnMgWzIsIDUsIDVdLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHRvQmFzZU91dCggc3RyLCBiYXNlSW4sIGJhc2VPdXQgKSB7XG4gICAgICAgIHZhciBqLFxuICAgICAgICAgICAgYXJyID0gWzBdLFxuICAgICAgICAgICAgYXJyTCxcbiAgICAgICAgICAgIGkgPSAwLFxuICAgICAgICAgICAgbGVuID0gc3RyLmxlbmd0aDtcblxuICAgICAgICBmb3IgKCA7IGkgPCBsZW47ICkge1xuICAgICAgICAgICAgZm9yICggYXJyTCA9IGFyci5sZW5ndGg7IGFyckwtLTsgYXJyW2FyckxdICo9IGJhc2VJbiApO1xuICAgICAgICAgICAgYXJyWyBqID0gMCBdICs9IEFMUEhBQkVULmluZGV4T2YoIHN0ci5jaGFyQXQoIGkrKyApICk7XG5cbiAgICAgICAgICAgIGZvciAoIDsgaiA8IGFyci5sZW5ndGg7IGorKyApIHtcblxuICAgICAgICAgICAgICAgIGlmICggYXJyW2pdID4gYmFzZU91dCAtIDEgKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICggYXJyW2ogKyAxXSA9PSBudWxsICkgYXJyW2ogKyAxXSA9IDA7XG4gICAgICAgICAgICAgICAgICAgIGFycltqICsgMV0gKz0gYXJyW2pdIC8gYmFzZU91dCB8IDA7XG4gICAgICAgICAgICAgICAgICAgIGFycltqXSAlPSBiYXNlT3V0O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBhcnIucmV2ZXJzZSgpO1xuICAgIH1cblxuXG4gICAgZnVuY3Rpb24gdG9FeHBvbmVudGlhbCggc3RyLCBlICkge1xuICAgICAgICByZXR1cm4gKCBzdHIubGVuZ3RoID4gMSA/IHN0ci5jaGFyQXQoMCkgKyAnLicgKyBzdHIuc2xpY2UoMSkgOiBzdHIgKSArXG4gICAgICAgICAgKCBlIDwgMCA/ICdlJyA6ICdlKycgKSArIGU7XG4gICAgfVxuXG5cbiAgICBmdW5jdGlvbiB0b0ZpeGVkUG9pbnQoIHN0ciwgZSApIHtcbiAgICAgICAgdmFyIGxlbiwgejtcblxuICAgICAgICAvLyBOZWdhdGl2ZSBleHBvbmVudD9cbiAgICAgICAgaWYgKCBlIDwgMCApIHtcblxuICAgICAgICAgICAgLy8gUHJlcGVuZCB6ZXJvcy5cbiAgICAgICAgICAgIGZvciAoIHogPSAnMC4nOyArK2U7IHogKz0gJzAnICk7XG4gICAgICAgICAgICBzdHIgPSB6ICsgc3RyO1xuXG4gICAgICAgIC8vIFBvc2l0aXZlIGV4cG9uZW50XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBsZW4gPSBzdHIubGVuZ3RoO1xuXG4gICAgICAgICAgICAvLyBBcHBlbmQgemVyb3MuXG4gICAgICAgICAgICBpZiAoICsrZSA+IGxlbiApIHtcbiAgICAgICAgICAgICAgICBmb3IgKCB6ID0gJzAnLCBlIC09IGxlbjsgLS1lOyB6ICs9ICcwJyApO1xuICAgICAgICAgICAgICAgIHN0ciArPSB6O1xuICAgICAgICAgICAgfSBlbHNlIGlmICggZSA8IGxlbiApIHtcbiAgICAgICAgICAgICAgICBzdHIgPSBzdHIuc2xpY2UoIDAsIGUgKSArICcuJyArIHN0ci5zbGljZShlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBzdHI7XG4gICAgfVxuXG5cbiAgICBmdW5jdGlvbiB0cnVuY2F0ZShuKSB7XG4gICAgICAgIG4gPSBwYXJzZUZsb2F0KG4pO1xuICAgICAgICByZXR1cm4gbiA8IDAgPyBtYXRoY2VpbChuKSA6IG1hdGhmbG9vcihuKTtcbiAgICB9XG5cblxuICAgIC8vIEVYUE9SVFxuXG5cbiAgICBCaWdOdW1iZXIgPSBhbm90aGVyKCk7XG5cbiAgICAvLyBBTUQuXG4gICAgaWYgKCB0eXBlb2YgZGVmaW5lID09ICdmdW5jdGlvbicgJiYgZGVmaW5lLmFtZCApIHtcbiAgICAgICAgZGVmaW5lKCBmdW5jdGlvbiAoKSB7IHJldHVybiBCaWdOdW1iZXI7IH0gKTtcblxuICAgIC8vIE5vZGUgYW5kIG90aGVyIGVudmlyb25tZW50cyB0aGF0IHN1cHBvcnQgbW9kdWxlLmV4cG9ydHMuXG4gICAgfSBlbHNlIGlmICggdHlwZW9mIG1vZHVsZSAhPSAndW5kZWZpbmVkJyAmJiBtb2R1bGUuZXhwb3J0cyApIHtcbiAgICAgICAgbW9kdWxlLmV4cG9ydHMgPSBCaWdOdW1iZXI7XG4gICAgICAgIGlmICggIWNyeXB0byApIHRyeSB7IGNyeXB0byA9IHJlcXVpcmUoJ2NyeXB0bycpOyB9IGNhdGNoIChlKSB7fVxuXG4gICAgLy8gQnJvd3Nlci5cbiAgICB9IGVsc2Uge1xuICAgICAgICBnbG9iYWwuQmlnTnVtYmVyID0gQmlnTnVtYmVyO1xuICAgIH1cbn0pKHRoaXMpO1xuIiwidmFyIHdlYjMgPSByZXF1aXJlKCcuL2xpYi93ZWIzJyk7XG53ZWIzLnByb3ZpZGVycy5IdHRwUHJvdmlkZXIgPSByZXF1aXJlKCcuL2xpYi93ZWIzL2h0dHBwcm92aWRlcicpO1xud2ViMy5wcm92aWRlcnMuUXRTeW5jUHJvdmlkZXIgPSByZXF1aXJlKCcuL2xpYi93ZWIzL3F0c3luYycpO1xud2ViMy5ldGguY29udHJhY3QgPSByZXF1aXJlKCcuL2xpYi93ZWIzL2NvbnRyYWN0Jyk7XG53ZWIzLmV0aC5uYW1lcmVnID0gcmVxdWlyZSgnLi9saWIvd2ViMy9uYW1lcmVnJyk7XG53ZWIzLmV0aC5zZW5kSUJBTlRyYW5zYWN0aW9uID0gcmVxdWlyZSgnLi9saWIvd2ViMy90cmFuc2ZlcicpO1xuXG4vLyBkb250IG92ZXJyaWRlIGdsb2JhbCB2YXJpYWJsZVxuaWYgKHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnICYmIHR5cGVvZiB3aW5kb3cud2ViMyA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICB3aW5kb3cud2ViMyA9IHdlYjM7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gd2ViMztcblxuIl19 diff --git a/libjsqrc/ethereumjs/dist/web3.min.js b/libjsqrc/ethereumjs/dist/web3.min.js index cf92525b8..1f1fcb189 100644 --- a/libjsqrc/ethereumjs/dist/web3.min.js +++ b/libjsqrc/ethereumjs/dist/web3.min.js @@ -1,2 +1,2 @@ -require=function t(e,n,r){function i(a,s){if(!n[a]){if(!e[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(o)return o(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var f=n[a]={exports:{}};e[a][0].call(f.exports,function(t){var n=e[a][1][t];return i(n?n:t)},f,f.exports,t,e,n,r)}return n[a].exports}for(var o="function"==typeof require&&require,a=0;ao;o+=64)n.push(this._outputFormatter(new a(t.dynamicPart().substr(o+64,64))));return n}return this._outputFormatter(t)},u.prototype.sliceParam=function(t,e,n){return"bytes"===this._mode?a.decodeBytes(t,e):s(n)?a.decodeArray(t,e):a.decodeParam(t,e)};var c=function(t){this._types=t};c.prototype._requireType=function(t){var e=this._types.filter(function(e){return e.isType(t)})[0];if(!e)throw Error("invalid solidity type!: "+t);return e},c.prototype._formatInput=function(t,e){return this._requireType(t).formatInput(e,s(t))},c.prototype.encodeParam=function(t,e){return this._formatInput(t,e).encode()},c.prototype.encodeParams=function(t,e){var n=this,r=t.map(function(t,r){return n._formatInput(t,e[r])});return a.encodeList(r)},c.prototype.decodeParam=function(t,e){return this.decodeParams([t],e)[0]},c.prototype.decodeParams=function(t,e){var n=this;return t.map(function(t,r){var i=n._requireType(t),o=i.sliceParam(e,r,t);return i.formatOutput(o,s(t))})};var f=new c([new u({name:"address",match:"strict",mode:"value",inputFormatter:o.formatInputInt,outputFormatter:o.formatOutputAddress}),new u({name:"bool",match:"strict",mode:"value",inputFormatter:o.formatInputBool,outputFormatter:o.formatOutputBool}),new u({name:"int",match:"prefix",mode:"value",inputFormatter:o.formatInputInt,outputFormatter:o.formatOutputInt}),new u({name:"uint",match:"prefix",mode:"value",inputFormatter:o.formatInputInt,outputFormatter:o.formatOutputUInt}),new u({name:"bytes",match:"strict",mode:"bytes",inputFormatter:o.formatInputDynamicBytes,outputFormatter:o.formatOutputDynamicBytes}),new u({name:"bytes",match:"prefix",mode:"value",inputFormatter:o.formatInputBytes,outputFormatter:o.formatOutputBytes}),new u({name:"real",match:"prefix",mode:"value",inputFormatter:o.formatInputReal,outputFormatter:o.formatOutputReal}),new u({name:"ureal",match:"prefix",mode:"value",inputFormatter:o.formatInputReal,outputFormatter:o.formatOutputUReal})]);e.exports=f},{"../utils/utils":7,"./formatters":2,"./param":3,"bignumber.js":"bignumber.js"}],2:[function(t,e,n){var r=t("bignumber.js"),i=t("../utils/utils"),o=t("../utils/config"),a=t("./param"),s=function(t){var e=2*o.ETH_PADDING;r.config(o.ETH_BIGNUMBER_ROUNDING_MODE);var n=i.padLeft(i.toTwosComplement(t).round().toString(16),e);return new a(n)},u=function(t){var e=i.fromAscii(t,o.ETH_PADDING).substr(2);return new a(e)},c=function(t){var e=i.fromAscii(t,o.ETH_PADDING).substr(2);return new a(s(t.length).value+e,32)},f=function(t){var e="000000000000000000000000000000000000000000000000000000000000000"+(t?"1":"0");return new a(e)},l=function(t){return s(new r(t).times(new r(2).pow(128)))},p=function(t){return"1"===new r(t.substr(0,1),16).toString(2).substr(0,1)},h=function(t){var e=t.staticPart()||"0";return p(e)?new r(e,16).minus(new r("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",16)).minus(1):new r(e,16)},m=function(t){var e=t.staticPart()||"0";return new r(e,16)},d=function(t){return h(t).dividedBy(new r(2).pow(128))},g=function(t){return m(t).dividedBy(new r(2).pow(128))},y=function(t){return"0000000000000000000000000000000000000000000000000000000000000001"===t.staticPart()?!0:!1},v=function(t){return i.toAscii(t.staticPart())},w=function(t){return i.toAscii(t.dynamicPart().slice(64))},b=function(t){var e=t.staticPart();return"0x"+e.slice(e.length-40,e.length)};e.exports={formatInputInt:s,formatInputBytes:u,formatInputDynamicBytes:c,formatInputBool:f,formatInputReal:l,formatOutputInt:h,formatOutputUInt:m,formatOutputReal:d,formatOutputUReal:g,formatOutputBool:y,formatOutputBytes:v,formatOutputDynamicBytes:w,formatOutputAddress:b}},{"../utils/config":5,"../utils/utils":7,"./param":3,"bignumber.js":"bignumber.js"}],3:[function(t,e,n){var r=t("../utils/utils"),i=function(t,e){this.value=t||"",this.offset=e};i.prototype.dynamicPartLength=function(){return this.dynamicPart().length/2},i.prototype.withOffset=function(t){return new i(this.value,t)},i.prototype.combine=function(t){return new i(this.value+t.value)},i.prototype.isDynamic=function(){return this.value.length>64||void 0!==this.offset},i.prototype.offsetAsBytes=function(){return this.isDynamic()?r.padLeft(r.toTwosComplement(this.offset).toString(16),64):""},i.prototype.staticPart=function(){return this.isDynamic()?this.offsetAsBytes():this.value},i.prototype.dynamicPart=function(){return this.isDynamic()?this.value:""},i.prototype.encode=function(){return this.staticPart()+this.dynamicPart()},i.encodeList=function(t){var e=32*t.length,n=t.map(function(t){if(!t.isDynamic())return t;var n=e;return e+=t.dynamicPartLength(),t.withOffset(n)});return n.reduce(function(t,e){return t+e.dynamicPart()},n.reduce(function(t,e){return t+e.staticPart()},""))},i.decodeParam=function(t,e){return e=e||0,new i(t.substr(64*e,64))};var o=function(t,e){return parseInt("0x"+t.substr(64*e,64))};i.decodeBytes=function(t,e){e=e||0;var n=o(t,e);return new i(t.substr(2*n,128),0)},i.decodeArray=function(t,e){e=e||0;var n=o(t,e),r=parseInt("0x"+t.substr(2*n,64));return new i(t.substr(2*n,64*(r+1)),0)},e.exports=i},{"../utils/utils":7}],4:[function(t,e,n){"use strict";n.XMLHttpRequest="undefined"==typeof XMLHttpRequest?{}:XMLHttpRequest},{}],5:[function(t,e,n){var r=t("bignumber.js"),i=["wei","kwei","Mwei","Gwei","szabo","finney","femtoether","picoether","nanoether","microether","milliether","nano","micro","milli","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:i,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:r.ROUND_DOWN},ETH_POLLING_TIMEOUT:1e3,defaultBlock:"latest",defaultAccount:void 0}},{"bignumber.js":"bignumber.js"}],6:[function(t,e,n){var r=t("./utils"),i=t("crypto-js/sha3");e.exports=function(t,e){return"0x"!==t.substr(0,2)||e||(console.warn("requirement of using web3.fromAscii before sha3 is deprecated"),console.warn("new usage: 'web3.sha3(\"hello\")'"),console.warn("see https://github.com/ethereum/web3.js/pull/205"),console.warn("if you need to hash hex value, you can do 'sha3(\"0xfff\", true)'"),t=r.toAscii(t)),i(t,{outputLength:256}).toString()}},{"./utils":7,"crypto-js/sha3":33}],7:[function(t,e,n){var r=t("bignumber.js"),i={wei:"1",kwei:"1000",ada:"1000",femtoether:"1000",mwei:"1000000",babbage:"1000000",picoether:"1000000",gwei:"1000000000",shannon:"1000000000",nanoether:"1000000000",nano:"1000000000",szabo:"1000000000000",microether:"1000000000000",micro:"1000000000000",finney:"1000000000000000",milliether:"1000000000000000",milli:"1000000000000000",ether:"1000000000000000000",kether:"1000000000000000000000",grand:"1000000000000000000000",einstein:"1000000000000000000000",mether:"1000000000000000000000000",gether:"1000000000000000000000000000",tether:"1000000000000000000000000000000"},o=function(t,e,n){return new Array(e-t.length+1).join(n?n:"0")+t},a=function(t){var e="",n=0,r=t.length;for("0x"===t.substring(0,2)&&(n=2);r>n;n+=2){var i=parseInt(t.substr(n,2),16);if(0===i)break;e+=String.fromCharCode(i)}return e},s=function(t){for(var e="",n=0;nthis._inputTypes.length&&o.isObject(t[t.length-1])&&(e=t[t.length-1]),e.to=this._address,e.data="0x"+this.signature()+i.encodeParams(this._inputTypes,t),e},s.prototype.signature=function(){return a(this._name).slice(0,8)},s.prototype.unpackOutput=function(t){if(t){t=t.length>=2?t.slice(2):t;var e=i.decodeParams(this._outputTypes,t);return 1===e.length?e[0]:e}},s.prototype.call=function(){var t=Array.prototype.slice.call(arguments).filter(function(t){return void 0!==t}),e=this.extractCallback(t),n=this.toPayload(t);if(!e){var i=r.eth.call(n);return this.unpackOutput(i)}var o=this;r.eth.call(n,function(t,n){e(t,o.unpackOutput(n))})},s.prototype.sendTransaction=function(){var t=Array.prototype.slice.call(arguments).filter(function(t){return void 0!==t}),e=this.extractCallback(t),n=this.toPayload(t);return e?void r.eth.sendTransaction(n,e):r.eth.sendTransaction(n)},s.prototype.estimateGas=function(){var t=Array.prototype.slice.call(arguments),e=this.extractCallback(t),n=this.toPayload(t);return e?void r.eth.estimateGas(n,e):r.eth.estimateGas(n)},s.prototype.displayName=function(){return o.extractDisplayName(this._name)},s.prototype.typeName=function(){return o.extractTypeName(this._name)},s.prototype.request=function(){var t=Array.prototype.slice.call(arguments),e=this.extractCallback(t),n=this.toPayload(t),r=this.unpackOutput.bind(this);return{callback:e,payload:n,format:r}},s.prototype.execute=function(){var t=!this._constant;return t?this.sendTransaction.apply(this,Array.prototype.slice.call(arguments)):this.call.apply(this,Array.prototype.slice.call(arguments))},s.prototype.attachToContract=function(t){var e=this.execute.bind(this);e.request=this.request.bind(this),e.call=this.call.bind(this),e.sendTransaction=this.sendTransaction.bind(this),e.estimateGas=this.estimateGas.bind(this);var n=this.displayName();t[n]||(t[n]=e),t[n][this.typeName()]=e},e.exports=s},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9}],19:[function(t,e,n){"use strict";var r=t("xmlhttprequest").XMLHttpRequest,i=t("./errors"),o=function(t){this.host=t||"http://localhost:8545"};o.prototype.send=function(t){var e=new r;e.open("POST",this.host,!1);try{e.send(JSON.stringify(t))}catch(n){throw i.InvalidConnection(this.host)}var o=e.responseText;try{o=JSON.parse(o)}catch(a){throw i.InvalidResponse(o)}return o},o.prototype.sendAsync=function(t,e){var n=new r;n.onreadystatechange=function(){if(4===n.readyState){var t=n.responseText,r=null;try{t=JSON.parse(t)}catch(o){r=i.InvalidResponse(t)}e(r,t)}},n.open("POST",this.host,!0);try{n.send(JSON.stringify(t))}catch(o){e(i.InvalidConnection(this.host))}},e.exports=o},{"./errors":13,xmlhttprequest:4}],20:[function(t,e,n){var r=t("../utils/utils"),i=function(t){this._iban=t};i.prototype.isValid=function(){return r.isIBAN(this._iban)},i.prototype.isDirect=function(){return 34===this._iban.length},i.prototype.isIndirect=function(){return 20===this._iban.length},i.prototype.checksum=function(){return this._iban.substr(2,2)},i.prototype.institution=function(){return this.isIndirect()?this._iban.substr(7,4):""},i.prototype.client=function(){return this.isIndirect()?this._iban.substr(11):""},i.prototype.address=function(){return this.isDirect()?this._iban.substr(4):""},e.exports=i},{"../utils/utils":7}],21:[function(t,e,n){var r=function(){return arguments.callee._singletonInstance?arguments.callee._singletonInstance:(arguments.callee._singletonInstance=this,void(this.messageId=1))};r.getInstance=function(){var t=new r;return t},r.prototype.toPayload=function(t,e){return t||console.error("jsonrpc method should be specified!"),{jsonrpc:"2.0",method:t,params:e||[],id:this.messageId++}},r.prototype.isValidResponse=function(t){return!!t&&!t.error&&"2.0"===t.jsonrpc&&"number"==typeof t.id&&void 0!==t.result},r.prototype.toBatchPayload=function(t){var e=this;return t.map(function(t){return e.toPayload(t.method,t.params)})},e.exports=r},{}],22:[function(t,e,n){var r=t("./requestmanager"),i=t("../utils/utils"),o=t("./errors"),a=function(t){this.name=t.name,this.call=t.call,this.params=t.params||0,this.inputFormatter=t.inputFormatter,this.outputFormatter=t.outputFormatter};a.prototype.getCall=function(t){return i.isFunction(this.call)?this.call(t):this.call},a.prototype.extractCallback=function(t){return i.isFunction(t[t.length-1])?t.pop():void 0},a.prototype.validateArgs=function(t){if(t.length!==this.params)throw o.InvalidNumberOfParams()},a.prototype.formatInput=function(t){return this.inputFormatter?this.inputFormatter.map(function(e,n){return e?e(t[n]):t[n]}):t},a.prototype.formatOutput=function(t){return this.outputFormatter&&null!==t?this.outputFormatter(t):t},a.prototype.attachToObject=function(t){var e=this.send.bind(this);e.request=this.request.bind(this),e.call=this.call;var n=this.name.split(".");n.length>1?(t[n[0]]=t[n[0]]||{},t[n[0]][n[1]]=e):t[n[0]]=e},a.prototype.toPayload=function(t){var e=this.getCall(t),n=this.extractCallback(t),r=this.formatInput(t);return this.validateArgs(r),{method:e,params:r,callback:n}},a.prototype.request=function(){var t=this.toPayload(Array.prototype.slice.call(arguments));return t.format=this.formatOutput.bind(this),t},a.prototype.send=function(){var t=this.toPayload(Array.prototype.slice.call(arguments));if(t.callback){var e=this;return r.getInstance().sendAsync(t,function(n,r){t.callback(n,e.formatOutput(r))})}return this.formatOutput(r.getInstance().send(t))},e.exports=a},{"../utils/utils":7,"./errors":13,"./requestmanager":27}],23:[function(t,e,n){var r=t("./contract"),i="0xc6d9d2cd449a754c494264e1809c50e34d64562b",o=[{constant:!0,inputs:[{name:"_owner",type:"address"}],name:"name",outputs:[{name:"o_name",type:"bytes32"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"owner",outputs:[{name:"",type:"address"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"content",outputs:[{name:"",type:"bytes32"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"addr",outputs:[{name:"",type:"address"}],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"}],name:"reserve",outputs:[],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"subRegistrar",outputs:[{name:"o_subRegistrar",type:"address"}],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_newOwner",type:"address"}],name:"transfer",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_registrar",type:"address"}],name:"setSubRegistrar",outputs:[],type:"function"},{constant:!1,inputs:[],name:"Registrar",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_a",type:"address"},{name:"_primary",type:"bool"}],name:"setAddress",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_content",type:"bytes32"}],name:"setContent",outputs:[], -type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"}],name:"disown",outputs:[],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"register",outputs:[{name:"",type:"address"}],type:"function"},{anonymous:!1,inputs:[{indexed:!0,name:"name",type:"bytes32"}],name:"Changed",type:"event"},{anonymous:!1,inputs:[{indexed:!0,name:"name",type:"bytes32"},{indexed:!0,name:"addr",type:"address"}],name:"PrimaryChanged",type:"event"}];e.exports=r(o).at(i)},{"./contract":11}],24:[function(t,e,n){var r=t("../utils/utils"),i=t("./property"),o=[],a=[new i({name:"listening",getter:"net_listening"}),new i({name:"peerCount",getter:"net_peerCount",outputFormatter:r.toDecimal})];e.exports={methods:o,properties:a}},{"../utils/utils":7,"./property":25}],25:[function(t,e,n){var r=t("./requestmanager"),i=function(t){this.name=t.name,this.getter=t.getter,this.setter=t.setter,this.outputFormatter=t.outputFormatter,this.inputFormatter=t.inputFormatter};i.prototype.formatInput=function(t){return this.inputFormatter?this.inputFormatter(t):t},i.prototype.formatOutput=function(t){return this.outputFormatter&&null!==t?this.outputFormatter(t):t},i.prototype.attachToObject=function(t){var e={get:this.get.bind(this)},n=this.name.split("."),r=n[0];n.length>1&&(t[n[0]]=t[n[0]]||{},t=t[n[0]],r=n[1]),Object.defineProperty(t,r,e);var i=function(t,e){return t+e.charAt(0).toUpperCase()+e.slice(1)};t[i("get",r)]=this.getAsync.bind(this)},i.prototype.get=function(){return this.formatOutput(r.getInstance().send({method:this.getter}))},i.prototype.getAsync=function(t){var e=this;r.getInstance().sendAsync({method:this.getter},function(n,r){return n?t(n):void t(n,e.formatOutput(r))})},e.exports=i},{"./requestmanager":27}],26:[function(t,e,n){var r=function(){};r.prototype.send=function(t){var e=navigator.qt.callMethod(JSON.stringify(t));return JSON.parse(e)},e.exports=r},{}],27:[function(t,e,n){var r=t("./jsonrpc"),i=t("../utils/utils"),o=t("../utils/config"),a=t("./errors"),s=function(t){return arguments.callee._singletonInstance?arguments.callee._singletonInstance:(arguments.callee._singletonInstance=this,this.provider=t,this.polls=[],this.timeout=null,void this.poll())};s.getInstance=function(){var t=new s;return t},s.prototype.send=function(t){if(!this.provider)return console.error(a.InvalidProvider()),null;var e=r.getInstance().toPayload(t.method,t.params),n=this.provider.send(e);if(!r.getInstance().isValidResponse(n))throw a.InvalidResponse(n);return n.result},s.prototype.sendAsync=function(t,e){if(!this.provider)return e(a.InvalidProvider());var n=r.getInstance().toPayload(t.method,t.params);this.provider.sendAsync(n,function(t,n){return t?e(t):r.getInstance().isValidResponse(n)?void e(null,n.result):e(a.InvalidResponse(n))})},s.prototype.sendBatch=function(t,e){if(!this.provider)return e(a.InvalidProvider());var n=r.getInstance().toBatchPayload(t);this.provider.sendAsync(n,function(t,n){return t?e(t):i.isArray(n)?void e(t,n):e(a.InvalidResponse(n))})},s.prototype.setProvider=function(t){this.provider=t},s.prototype.startPolling=function(t,e,n,r){this.polls.push({data:t,id:e,callback:n,uninstall:r})},s.prototype.stopPolling=function(t){for(var e=this.polls.length;e--;){var n=this.polls[e];n.id===t&&this.polls.splice(e,1)}},s.prototype.reset=function(){this.polls.forEach(function(t){t.uninstall(t.id)}),this.polls=[],this.timeout&&(clearTimeout(this.timeout),this.timeout=null),this.poll()},s.prototype.poll=function(){if(this.timeout=setTimeout(this.poll.bind(this),o.ETH_POLLING_TIMEOUT),this.polls.length){if(!this.provider)return void console.error(a.InvalidProvider());var t=r.getInstance().toBatchPayload(this.polls.map(function(t){return t.data})),e=this;this.provider.sendAsync(t,function(t,n){if(!t){if(!i.isArray(n))throw a.InvalidResponse(n);n.map(function(t,n){return t.callback=e.polls[n].callback,t}).filter(function(t){var e=r.getInstance().isValidResponse(t);return e||t.callback(a.InvalidResponse(t)),e}).filter(function(t){return i.isArray(t.result)&&t.result.length>0}).forEach(function(t){t.callback(null,t.result)})}})}},e.exports=s},{"../utils/config":5,"../utils/utils":7,"./errors":13,"./jsonrpc":21}],28:[function(t,e,n){var r=t("./method"),i=t("./formatters"),o=new r({name:"post",call:"shh_post",params:1,inputFormatter:[i.inputPostFormatter]}),a=new r({name:"newIdentity",call:"shh_newIdentity",params:0}),s=new r({name:"hasIdentity",call:"shh_hasIdentity",params:1}),u=new r({name:"newGroup",call:"shh_newGroup",params:0}),c=new r({name:"addToGroup",call:"shh_addToGroup",params:0}),f=[o,a,s,u,c];e.exports={methods:f}},{"./formatters":17,"./method":22}],29:[function(t,e,n){var r=t("../web3"),i=t("./icap"),o=t("./namereg"),a=t("./contract"),s=function(t,e,n,r){var a=new i(e);if(!a.isValid())throw new Error("invalid iban address");if(a.isDirect())return u(t,a.address(),n,r);if(!r){var s=o.addr(a.institution());return c(t,s,n,a.client())}o.addr(a.insitution(),function(e,i){return c(t,i,n,a.client(),r)})},u=function(t,e,n,i){return r.eth.sendTransaction({address:e,from:t,value:n},i)},c=function(t,e,n,r,i){var o=[{constant:!1,inputs:[{name:"name",type:"bytes32"}],name:"deposit",outputs:[],type:"function"}];return a(o).at(e).deposit(r,{from:t,value:n},i)};e.exports=s},{"../web3":9,"./contract":11,"./icap":20,"./namereg":23}],30:[function(t,e,n){var r=t("./method"),i=function(){var t=function(t){var e=t[0];switch(e){case"latest":return t.pop(),this.params=0,"eth_newBlockFilter";case"pending":return t.pop(),this.params=0,"eth_newPendingTransactionFilter";default:return"eth_newFilter"}},e=new r({name:"newFilter",call:t,params:1}),n=new r({name:"uninstallFilter",call:"eth_uninstallFilter",params:1}),i=new r({name:"getLogs",call:"eth_getFilterLogs",params:1}),o=new r({name:"poll",call:"eth_getFilterChanges",params:1});return[e,n,i,o]},o=function(){var t=new r({name:"newFilter",call:"shh_newFilter",params:1}),e=new r({name:"uninstallFilter",call:"shh_uninstallFilter",params:1}),n=new r({name:"getLogs",call:"shh_getMessages",params:1}),i=new r({name:"poll",call:"shh_getFilterChanges",params:1});return[t,e,n,i]};e.exports={eth:i,shh:o}},{"./method":22}],31:[function(t,e,n){},{}],32:[function(t,e,n){!function(t,r){"object"==typeof n?e.exports=n=r():"function"==typeof define&&define.amd?define([],r):t.CryptoJS=r()}(this,function(){var t=t||function(t,e){var n={},r=n.lib={},i=r.Base=function(){function t(){}return{extend:function(e){t.prototype=this;var n=new t;return e&&n.mixIn(e),n.hasOwnProperty("init")||(n.init=function(){n.$super.init.apply(this,arguments)}),n.init.prototype=n,n.$super=this,n},create:function(){var t=this.extend();return t.init.apply(t,arguments),t},init:function(){},mixIn:function(t){for(var e in t)t.hasOwnProperty(e)&&(this[e]=t[e]);t.hasOwnProperty("toString")&&(this.toString=t.toString)},clone:function(){return this.init.prototype.extend(this)}}}(),o=r.WordArray=i.extend({init:function(t,n){t=this.words=t||[],this.sigBytes=n!=e?n:4*t.length},toString:function(t){return(t||s).stringify(this)},concat:function(t){var e=this.words,n=t.words,r=this.sigBytes,i=t.sigBytes;if(this.clamp(),r%4)for(var o=0;i>o;o++){var a=n[o>>>2]>>>24-o%4*8&255;e[r+o>>>2]|=a<<24-(r+o)%4*8}else for(var o=0;i>o;o+=4)e[r+o>>>2]=n[o>>>2];return this.sigBytes+=i,this},clamp:function(){var e=this.words,n=this.sigBytes;e[n>>>2]&=4294967295<<32-n%4*8,e.length=t.ceil(n/4)},clone:function(){var t=i.clone.call(this);return t.words=this.words.slice(0),t},random:function(e){for(var n,r=[],i=function(e){var e=e,n=987654321,r=4294967295;return function(){n=36969*(65535&n)+(n>>16)&r,e=18e3*(65535&e)+(e>>16)&r;var i=(n<<16)+e&r;return i/=4294967296,i+=.5,i*(t.random()>.5?1:-1)}},a=0;e>a;a+=4){var s=i(4294967296*(n||t.random()));n=987654071*s(),r.push(4294967296*s()|0)}return new o.init(r,e)}}),a=n.enc={},s=a.Hex={stringify:function(t){for(var e=t.words,n=t.sigBytes,r=[],i=0;n>i;i++){var o=e[i>>>2]>>>24-i%4*8&255;r.push((o>>>4).toString(16)),r.push((15&o).toString(16))}return r.join("")},parse:function(t){for(var e=t.length,n=[],r=0;e>r;r+=2)n[r>>>3]|=parseInt(t.substr(r,2),16)<<24-r%8*4;return new o.init(n,e/2)}},u=a.Latin1={stringify:function(t){for(var e=t.words,n=t.sigBytes,r=[],i=0;n>i;i++){var o=e[i>>>2]>>>24-i%4*8&255;r.push(String.fromCharCode(o))}return r.join("")},parse:function(t){for(var e=t.length,n=[],r=0;e>r;r++)n[r>>>2]|=(255&t.charCodeAt(r))<<24-r%4*8;return new o.init(n,e)}},c=a.Utf8={stringify:function(t){try{return decodeURIComponent(escape(u.stringify(t)))}catch(e){throw new Error("Malformed UTF-8 data")}},parse:function(t){return u.parse(unescape(encodeURIComponent(t)))}},f=r.BufferedBlockAlgorithm=i.extend({reset:function(){this._data=new o.init,this._nDataBytes=0},_append:function(t){"string"==typeof t&&(t=c.parse(t)),this._data.concat(t),this._nDataBytes+=t.sigBytes},_process:function(e){var n=this._data,r=n.words,i=n.sigBytes,a=this.blockSize,s=4*a,u=i/s;u=e?t.ceil(u):t.max((0|u)-this._minBufferSize,0);var c=u*a,f=t.min(4*c,i);if(c){for(var l=0;c>l;l+=a)this._doProcessBlock(r,l);var p=r.splice(0,c);n.sigBytes-=f}return new o.init(p,f)},clone:function(){var t=i.clone.call(this);return t._data=this._data.clone(),t},_minBufferSize:0}),l=(r.Hasher=f.extend({cfg:i.extend(),init:function(t){this.cfg=this.cfg.extend(t),this.reset()},reset:function(){f.reset.call(this),this._doReset()},update:function(t){return this._append(t),this._process(),this},finalize:function(t){t&&this._append(t);var e=this._doFinalize();return e},blockSize:16,_createHelper:function(t){return function(e,n){return new t.init(n).finalize(e)}},_createHmacHelper:function(t){return function(e,n){return new l.HMAC.init(t,n).finalize(e)}}}),n.algo={});return n}(Math);return t})},{}],33:[function(t,e,n){!function(r,i,o){"object"==typeof n?e.exports=n=i(t("./core"),t("./x64-core")):"function"==typeof define&&define.amd?define(["./core","./x64-core"],i):i(r.CryptoJS)}(this,function(t){return function(e){var n=t,r=n.lib,i=r.WordArray,o=r.Hasher,a=n.x64,s=a.Word,u=n.algo,c=[],f=[],l=[];!function(){for(var t=1,e=0,n=0;24>n;n++){c[t+5*e]=(n+1)*(n+2)/2%64;var r=e%5,i=(2*t+3*e)%5;t=r,e=i}for(var t=0;5>t;t++)for(var e=0;5>e;e++)f[t+5*e]=e+(2*t+3*e)%5*5;for(var o=1,a=0;24>a;a++){for(var u=0,p=0,h=0;7>h;h++){if(1&o){var m=(1<m?p^=1<t;t++)p[t]=s.create()}();var h=u.SHA3=o.extend({cfg:o.cfg.extend({outputLength:512}),_doReset:function(){for(var t=this._state=[],e=0;25>e;e++)t[e]=new s.init;this.blockSize=(1600-2*this.cfg.outputLength)/32},_doProcessBlock:function(t,e){for(var n=this._state,r=this.blockSize/2,i=0;r>i;i++){var o=t[e+2*i],a=t[e+2*i+1];o=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8),a=16711935&(a<<8|a>>>24)|4278255360&(a<<24|a>>>8);var s=n[i];s.high^=a,s.low^=o}for(var u=0;24>u;u++){for(var h=0;5>h;h++){for(var m=0,d=0,g=0;5>g;g++){var s=n[h+5*g];m^=s.high,d^=s.low}var y=p[h];y.high=m,y.low=d}for(var h=0;5>h;h++)for(var v=p[(h+4)%5],w=p[(h+1)%5],b=w.high,_=w.low,m=v.high^(b<<1|_>>>31),d=v.low^(_<<1|b>>>31),g=0;5>g;g++){var s=n[h+5*g];s.high^=m,s.low^=d}for(var x=1;25>x;x++){var s=n[x],F=s.high,I=s.low,B=c[x];if(32>B)var m=F<>>32-B,d=I<>>32-B;else var m=I<>>64-B,d=F<>>64-B;var N=p[f[x]];N.high=m,N.low=d}var O=p[0],A=n[0];O.high=A.high,O.low=A.low;for(var h=0;5>h;h++)for(var g=0;5>g;g++){var x=h+5*g,s=n[x],k=p[x],P=p[(h+1)%5+5*g],T=p[(h+2)%5+5*g];s.high=k.high^~P.high&T.high,s.low=k.low^~P.low&T.low}var s=n[0],D=l[u];s.high^=D.high,s.low^=D.low}},_doFinalize:function(){var t=this._data,n=t.words,r=(8*this._nDataBytes,8*t.sigBytes),o=32*this.blockSize;n[r>>>5]|=1<<24-r%32,n[(e.ceil((r+1)/o)*o>>>5)-1]|=128,t.sigBytes=4*n.length,this._process();for(var a=this._state,s=this.cfg.outputLength/8,u=s/8,c=[],f=0;u>f;f++){var l=a[f],p=l.high,h=l.low;p=16711935&(p<<8|p>>>24)|4278255360&(p<<24|p>>>8),h=16711935&(h<<8|h>>>24)|4278255360&(h<<24|h>>>8),c.push(h),c.push(p)}return new i.init(c,s)},clone:function(){for(var t=o.clone.call(this),e=t._state=this._state.slice(0),n=0;25>n;n++)e[n]=e[n].clone();return t}});n.SHA3=o._createHelper(h),n.HmacSHA3=o._createHmacHelper(h)}(Math),t.SHA3})},{"./core":32,"./x64-core":34}],34:[function(t,e,n){!function(r,i){"object"==typeof n?e.exports=n=i(t("./core")):"function"==typeof define&&define.amd?define(["./core"],i):i(r.CryptoJS)}(this,function(t){return function(e){{var n=t,r=n.lib,i=r.Base,o=r.WordArray,a=n.x64={};a.Word=i.extend({init:function(t,e){this.high=t,this.low=e}}),a.WordArray=i.extend({init:function(t,n){t=this.words=t||[],this.sigBytes=n!=e?n:8*t.length},toX32:function(){for(var t=this.words,e=t.length,n=[],r=0;e>r;r++){var i=t[r];n.push(i.high),n.push(i.low)}return o.create(n,this.sigBytes)},clone:function(){for(var t=i.clone.call(this),e=t.words=this.words.slice(0),n=e.length,r=0;n>r;r++)e[r]=e[r].clone();return t}})}}(),t})},{"./core":32}],"bignumber.js":[function(t,e,n){!function(n){"use strict";function r(t){function e(t,r){var i,o,a,s,u,c,f=this;if(!(f instanceof e))return z&&D(26,"constructor call without new",t),new e(t,r);if(null!=r&&W(r,2,64,C,"base")){if(r=0|r,c=t+"",10==r)return f=new e(t instanceof e?t:c),S(f,L+f.e+1,j);if((s="number"==typeof t)&&0*t!=0||!new RegExp("^-?"+(i="["+x.slice(0,r)+"]+")+"(?:\\."+i+")?$",37>r?"i":"").test(c))return d(f,c,s,r);s?(f.s=0>1/t?(c=c.slice(1),-1):1,z&&c.replace(/^0\.0*|\./,"").length>15&&D(C,_,t),s=!1):f.s=45===c.charCodeAt(0)?(c=c.slice(1),-1):1,c=n(c,10,r,f.s)}else{if(t instanceof e)return f.s=t.s,f.e=t.e,f.c=(t=t.c)?t.slice():t,void(C=0);if((s="number"==typeof t)&&0*t==0){if(f.s=0>1/t?(t=-t,-1):1,t===~~t){for(o=0,a=t;a>=10;a/=10,o++);return f.e=o,f.c=[t],void(C=0)}c=t+""}else{if(!g.test(c=t+""))return d(f,c,s);f.s=45===c.charCodeAt(0)?(c=c.slice(1),-1):1}}for((o=c.indexOf("."))>-1&&(c=c.replace(".","")),(a=c.search(/e/i))>0?(0>o&&(o=a),o+=+c.slice(a+1),c=c.substring(0,a)):0>o&&(o=c.length),a=0;48===c.charCodeAt(a);a++);for(u=c.length;48===c.charCodeAt(--u););if(c=c.slice(a,u+1))if(u=c.length,s&&z&&u>15&&D(C,_,f.s*t),o=o-a-1,o>M)f.c=f.e=null;else if(G>o)f.c=[f.e=0];else{if(f.e=o,f.c=[],a=(o+1)%I,0>o&&(a+=I),u>a){for(a&&f.c.push(+c.slice(0,a)),u-=I;u>a;)f.c.push(+c.slice(a,a+=I));c=c.slice(a),a=I-c.length}else a-=u;for(;a--;c+="0");f.c.push(+c)}else f.c=[f.e=0];C=0}function n(t,n,r,i){var a,s,u,f,p,h,m,d=t.indexOf("."),g=L,y=j;for(37>r&&(t=t.toLowerCase()),d>=0&&(u=V,V=0,t=t.replace(".",""),m=new e(r),p=m.pow(t.length-d),V=u,m.c=c(l(o(p.c),p.e),10,n),m.e=m.c.length),h=c(t,r,n),s=u=h.length;0==h[--u];h.pop());if(!h[0])return"0";if(0>d?--s:(p.c=h,p.e=s,p.s=i,p=E(p,m,g,y,n),h=p.c,f=p.r,s=p.e),a=s+g+1,d=h[a],u=n/2,f=f||0>a||null!=h[a+1],f=4>y?(null!=d||f)&&(0==y||y==(p.s<0?3:2)):d>u||d==u&&(4==y||f||6==y&&1&h[a-1]||y==(p.s<0?8:7)),1>a||!h[0])t=f?l("1",-g):"0";else{if(h.length=a,f)for(--n;++h[--a]>n;)h[a]=0,a||(++s,h.unshift(1));for(u=h.length;!h[--u];);for(d=0,t="";u>=d;t+=x.charAt(h[d++]));t=l(t,s)}return t}function h(t,n,r,i){var a,s,u,c,p;if(r=null!=r&&W(r,0,8,i,b)?0|r:j,!t.c)return t.toString();if(a=t.c[0],u=t.e,null==n)p=o(t.c),p=19==i||24==i&&q>=u?f(p,u):l(p,u);else if(t=S(new e(t),n,r),s=t.e,p=o(t.c),c=p.length,19==i||24==i&&(s>=n||q>=s)){for(;n>c;p+="0",c++);p=f(p,s)}else if(n-=u,p=l(p,s),s+1>c){if(--n>0)for(p+=".";n--;p+="0");}else if(n+=s-c,n>0)for(s+1==c&&(p+=".");n--;p+="0");return t.s<0&&a?"-"+p:p}function k(t,n){var r,i,o=0;for(u(t[0])&&(t=t[0]),r=new e(t[0]);++ot||t>n||t!=p(t))&&D(r,(i||"decimal places")+(e>t||t>n?" out of range":" not an integer"),t),!0}function T(t,e,n){for(var r=1,i=e.length;!e[--i];e.pop());for(i=e[0];i>=10;i/=10,r++);return(n=r+n*I-1)>M?t.c=t.e=null:G>n?t.c=[t.e=0]:(t.e=n,t.c=e),t}function D(t,e,n){var r=new Error(["new BigNumber","cmp","config","div","divToInt","eq","gt","gte","lt","lte","minus","mod","plus","precision","random","round","shift","times","toDigits","toExponential","toFixed","toFormat","toFraction","pow","toPrecision","toString","BigNumber"][t]+"() "+e+": "+n);throw r.name="BigNumber Error",C=0,r}function S(t,e,n,r){var i,o,a,s,u,c,f,l=t.c,p=N;if(l){t:{for(i=1,s=l[0];s>=10;s/=10,i++);if(o=e-i,0>o)o+=I,a=e,u=l[c=0],f=u/p[i-a-1]%10|0;else if(c=y((o+1)/I),c>=l.length){if(!r)break t;for(;l.length<=c;l.push(0));u=f=0,i=1,o%=I,a=o-I+1}else{for(u=s=l[c],i=1;s>=10;s/=10,i++);o%=I,a=o-I+i,f=0>a?0:u/p[i-a-1]%10|0}if(r=r||0>e||null!=l[c+1]||(0>a?u:u%p[i-a-1]),r=4>n?(f||r)&&(0==n||n==(t.s<0?3:2)):f>5||5==f&&(4==n||r||6==n&&(o>0?a>0?u/p[i-a]:0:l[c-1])%10&1||n==(t.s<0?8:7)),1>e||!l[0])return l.length=0,r?(e-=t.e+1,l[0]=p[e%I],t.e=-e||0):l[0]=t.e=0,t;if(0==o?(l.length=c,s=1,c--):(l.length=c+1,s=p[I-o],l[c]=a>0?v(u/p[i-a]%p[a])*s:0),r)for(;;){if(0==c){for(o=1,a=l[0];a>=10;a/=10,o++);for(a=l[0]+=s,s=1;a>=10;a/=10,s++);o!=s&&(t.e++,l[0]==F&&(l[0]=1));break}if(l[c]+=s,l[c]!=F)break;l[c--]=0,s=1}for(o=l.length;0===l[--o];l.pop());}t.e>M?t.c=t.e=null:t.en?null!=(t=i[n++]):void 0};return a(e="DECIMAL_PLACES")&&W(t,0,A,2,e)&&(L=0|t),r[e]=L,a(e="ROUNDING_MODE")&&W(t,0,8,2,e)&&(j=0|t),r[e]=j,a(e="EXPONENTIAL_AT")&&(u(t)?W(t[0],-A,0,2,e)&&W(t[1],0,A,2,e)&&(q=0|t[0],U=0|t[1]):W(t,-A,A,2,e)&&(q=-(U=0|(0>t?-t:t)))),r[e]=[q,U],a(e="RANGE")&&(u(t)?W(t[0],-A,-1,2,e)&&W(t[1],1,A,2,e)&&(G=0|t[0],M=0|t[1]):W(t,-A,A,2,e)&&(0|t?G=-(M=0|(0>t?-t:t)):z&&D(2,e+" cannot be zero",t))),r[e]=[G,M],a(e="ERRORS")&&(t===!!t||1===t||0===t?(C=0,W=(z=!!t)?P:s):z&&D(2,e+w,t)),r[e]=z,a(e="CRYPTO")&&(t===!!t||1===t||0===t?(J=!(!t||!m||"object"!=typeof m),t&&!J&&z&&D(2,"crypto unavailable",m)):z&&D(2,e+w,t)),r[e]=J,a(e="MODULO_MODE")&&W(t,0,9,2,e)&&($=0|t),r[e]=$,a(e="POW_PRECISION")&&W(t,0,A,2,e)&&(V=0|t),r[e]=V,a(e="FORMAT")&&("object"==typeof t?X=t:z&&D(2,e+" not an object",t)),r[e]=X,r},e.max=function(){return k(arguments,R.lt)},e.min=function(){return k(arguments,R.gt)},e.random=function(){var t=9007199254740992,n=Math.random()*t&2097151?function(){return v(Math.random()*t)}:function(){return 8388608*(1073741824*Math.random()|0)+(8388608*Math.random()|0)};return function(t){var r,i,o,a,s,u=0,c=[],f=new e(H);if(t=null!=t&&W(t,0,A,14)?0|t:L,a=y(t/I),J)if(m&&m.getRandomValues){for(r=m.getRandomValues(new Uint32Array(a*=2));a>u;)s=131072*r[u]+(r[u+1]>>>11),s>=9e15?(i=m.getRandomValues(new Uint32Array(2)),r[u]=i[0],r[u+1]=i[1]):(c.push(s%1e14),u+=2);u=a/2}else if(m&&m.randomBytes){for(r=m.randomBytes(a*=7);a>u;)s=281474976710656*(31&r[u])+1099511627776*r[u+1]+4294967296*r[u+2]+16777216*r[u+3]+(r[u+4]<<16)+(r[u+5]<<8)+r[u+6],s>=9e15?m.randomBytes(7).copy(r,u):(c.push(s%1e14),u+=7);u=a/7}else z&&D(14,"crypto unavailable",m);if(!u)for(;a>u;)s=n(),9e15>s&&(c[u++]=s%1e14);for(a=c[--u],t%=I,a&&t&&(s=N[I-t],c[u]=v(a/s)*s);0===c[u];c.pop(),u--);if(0>u)c=[o=0];else{for(o=-1;0===c[0];c.shift(),o-=I);for(u=1,s=c[0];s>=10;s/=10,u++);I>u&&(o-=I-u)}return f.e=o,f.c=c,f}}(),E=function(){function t(t,e,n){var r,i,o,a,s=0,u=t.length,c=e%O,f=e/O|0;for(t=t.slice();u--;)o=t[u]%O,a=t[u]/O|0,r=f*o+a*c,i=c*o+r%O*O+s,s=(i/n|0)+(r/O|0)+f*a,t[u]=i%n;return s&&t.unshift(s),t}function n(t,e,n,r){var i,o;if(n!=r)o=n>r?1:-1;else for(i=o=0;n>i;i++)if(t[i]!=e[i]){o=t[i]>e[i]?1:-1;break}return o}function r(t,e,n,r){for(var i=0;n--;)t[n]-=i,i=t[n]1;t.shift());}return function(o,a,s,u,c){var f,l,p,h,m,d,g,y,w,b,_,x,B,N,O,A,k,P=o.s==a.s?1:-1,T=o.c,D=a.c;if(!(T&&T[0]&&D&&D[0]))return new e(o.s&&a.s&&(T?!D||T[0]!=D[0]:D)?T&&0==T[0]||!D?0*P:P/0:0/0);for(y=new e(P),w=y.c=[],l=o.e-a.e,P=s+l+1,c||(c=F,l=i(o.e/I)-i(a.e/I),P=P/I|0),p=0;D[p]==(T[p]||0);p++);if(D[p]>(T[p]||0)&&l--,0>P)w.push(1),h=!0;else{for(N=T.length,A=D.length,p=0,P+=2,m=v(c/(D[0]+1)),m>1&&(D=t(D,m,c),T=t(T,m,c),A=D.length,N=T.length),B=A,b=T.slice(0,A),_=b.length;A>_;b[_++]=0);k=D.slice(),k.unshift(0),O=D[0],D[1]>=c/2&&O++;do{if(m=0,f=n(D,b,A,_),0>f){if(x=b[0],A!=_&&(x=x*c+(b[1]||0)),m=v(x/O),m>1)for(m>=c&&(m=c-1),d=t(D,m,c),g=d.length,_=b.length;1==n(d,b,g,_);)m--,r(d,g>A?k:D,g,c),g=d.length,f=1;else 0==m&&(f=m=1),d=D.slice(),g=d.length;if(_>g&&d.unshift(0),r(b,d,_,c),_=b.length,-1==f)for(;n(D,b,A,_)<1;)m++,r(b,_>A?k:D,_,c),_=b.length}else 0===f&&(m++,b=[0]);w[p++]=m,b[0]?b[_++]=T[B]||0:(b=[T[B]],_=1)}while((B++=10;P/=10,p++);S(y,s+(y.e=p+l*I-1)+1,u,h)}else y.e=l,y.r=+h;return y}}(),d=function(){var t=/^(-?)0([xbo])/i,n=/^([^.]+)\.$/,r=/^\.([^.]+)$/,i=/^-?(Infinity|NaN)$/,o=/^\s*\+|^\s+|\s+$/g;return function(a,s,u,c){var f,l=u?s:s.replace(o,"");if(i.test(l))a.s=isNaN(l)?null:0>l?-1:1;else{if(!u&&(l=l.replace(t,function(t,e,n){return f="x"==(n=n.toLowerCase())?16:"b"==n?2:8,c&&c!=f?t:e}),c&&(f=c,l=l.replace(n,"$1").replace(r,"0.$1")),s!=l))return new e(l,f);z&&D(C,"not a"+(c?" base "+c:"")+" number",s),a.s=null}a.c=a.e=null,C=0}}(),R.absoluteValue=R.abs=function(){var t=new e(this);return t.s<0&&(t.s=1),t},R.ceil=function(){return S(new e(this),this.e+1,2)},R.comparedTo=R.cmp=function(t,n){return C=1,a(this,new e(t,n))},R.decimalPlaces=R.dp=function(){var t,e,n=this.c;if(!n)return null;if(t=((e=n.length-1)-i(this.e/I))*I,e=n[e])for(;e%10==0;e/=10,t--);return 0>t&&(t=0),t},R.dividedBy=R.div=function(t,n){return C=3,E(this,new e(t,n),L,j)},R.dividedToIntegerBy=R.divToInt=function(t,n){return C=4,E(this,new e(t,n),0,1)},R.equals=R.eq=function(t,n){return C=5,0===a(this,new e(t,n))},R.floor=function(){return S(new e(this),this.e+1,3)},R.greaterThan=R.gt=function(t,n){return C=6,a(this,new e(t,n))>0},R.greaterThanOrEqualTo=R.gte=function(t,n){return C=7,1===(n=a(this,new e(t,n)))||0===n},R.isFinite=function(){return!!this.c},R.isInteger=R.isInt=function(){return!!this.c&&i(this.e/I)>this.c.length-2},R.isNaN=function(){return!this.s},R.isNegative=R.isNeg=function(){return this.s<0},R.isZero=function(){return!!this.c&&0==this.c[0]},R.lessThan=R.lt=function(t,n){return C=8,a(this,new e(t,n))<0},R.lessThanOrEqualTo=R.lte=function(t,n){return C=9,-1===(n=a(this,new e(t,n)))||0===n},R.minus=R.sub=function(t,n){var r,o,a,s,u=this,c=u.s;if(C=10,t=new e(t,n),n=t.s,!c||!n)return new e(0/0);if(c!=n)return t.s=-n,u.plus(t);var f=u.e/I,l=t.e/I,p=u.c,h=t.c;if(!f||!l){if(!p||!h)return p?(t.s=-n,t):new e(h?u:0/0);if(!p[0]||!h[0])return h[0]?(t.s=-n,t):new e(p[0]?u:3==j?-0:0)}if(f=i(f),l=i(l),p=p.slice(),c=f-l){for((s=0>c)?(c=-c,a=p):(l=f,a=h),a.reverse(),n=c;n--;a.push(0));a.reverse()}else for(o=(s=(c=p.length)<(n=h.length))?c:n,c=n=0;o>n;n++)if(p[n]!=h[n]){s=p[n]0)for(;n--;p[r++]=0);for(n=F-1;o>c;){if(p[--o]0?(u=s,r=f):(a=-a,r=c),r.reverse();a--;r.push(0));r.reverse()}for(a=c.length,n=f.length,0>a-n&&(r=f,f=c,c=r,n=a),a=0;n;)a=(c[--n]=c[n]+f[n]+a)/F|0,c[n]%=F;return a&&(c.unshift(a),++u),T(t,c,u)},R.precision=R.sd=function(t){var e,n,r=this,i=r.c;if(null!=t&&t!==!!t&&1!==t&&0!==t&&(z&&D(13,"argument"+w,t),t!=!!t&&(t=null)),!i)return null;if(n=i.length-1,e=n*I+1,n=i[n]){for(;n%10==0;n/=10,e--);for(n=i[0];n>=10;n/=10,e++);}return t&&r.e+1>e&&(e=r.e+1),e},R.round=function(t,n){var r=new e(this);return(null==t||W(t,0,A,15))&&S(r,~~t+this.e+1,null!=n&&W(n,0,8,15,b)?0|n:j),r},R.shift=function(t){var n=this;return W(t,-B,B,16,"argument")?n.times("1e"+p(t)):new e(n.c&&n.c[0]&&(-B>t||t>B)?n.s*(0>t?0:1/0):n)},R.squareRoot=R.sqrt=function(){var t,n,r,a,s,u=this,c=u.c,f=u.s,l=u.e,p=L+4,h=new e("0.5");if(1!==f||!c||!c[0])return new e(!f||0>f&&(!c||c[0])?0/0:c?u:1/0);if(f=Math.sqrt(+u),0==f||f==1/0?(n=o(c),(n.length+l)%2==0&&(n+="0"),f=Math.sqrt(n),l=i((l+1)/2)-(0>l||l%2),f==1/0?n="1e"+l:(n=f.toExponential(),n=n.slice(0,n.indexOf("e")+1)+l),r=new e(n)):r=new e(f+""),r.c[0])for(l=r.e,f=l+p,3>f&&(f=0);;)if(s=r,r=h.times(s.plus(E(u,s,p,1))),o(s.c).slice(0,f)===(n=o(r.c)).slice(0,f)){if(r.ef&&(g=b,b=_,_=g,a=f,f=h,h=a),a=f+h,g=[];a--;g.push(0));for(y=F,v=O,a=h;--a>=0;){for(r=0,m=_[a]%v,d=_[a]/v|0,u=f,s=a+u;s>a;)l=b[--u]%v,p=b[u]/v|0,c=d*l+p*m,l=m*l+c%v*v+g[s]+r,r=(l/y|0)+(c/v|0)+d*p,g[s--]=l%y;g[s]=r}return r?++o:g.shift(),T(t,g,o)},R.toDigits=function(t,n){var r=new e(this);return t=null!=t&&W(t,1,A,18,"precision")?0|t:null,n=null!=n&&W(n,0,8,18,b)?0|n:j,t?S(r,t,n):r},R.toExponential=function(t,e){return h(this,null!=t&&W(t,0,A,19)?~~t+1:null,e,19)},R.toFixed=function(t,e){return h(this,null!=t&&W(t,0,A,20)?~~t+this.e+1:null,e,20)},R.toFormat=function(t,e){var n=h(this,null!=t&&W(t,0,A,21)?~~t+this.e+1:null,e,21);if(this.c){var r,i=n.split("."),o=+X.groupSize,a=+X.secondaryGroupSize,s=X.groupSeparator,u=i[0],c=i[1],f=this.s<0,l=f?u.slice(1):u,p=l.length;if(a&&(r=o,o=a,a=r,p-=r),o>0&&p>0){for(r=p%o||o,u=l.substr(0,r);p>r;r+=o)u+=s+l.substr(r,o);a>0&&(u+=s+l.slice(r)),f&&(u="-"+u)}n=c?u+X.decimalSeparator+((a=+X.fractionGroupSize)?c.replace(new RegExp("\\d{"+a+"}\\B","g"),"$&"+X.fractionGroupSeparator):c):u}return n},R.toFraction=function(t){var n,r,i,a,s,u,c,f,l,p=z,h=this,m=h.c,d=new e(H),g=r=new e(H),y=c=new e(H);if(null!=t&&(z=!1,u=new e(t),z=p,(!(p=u.isInt())||u.lt(H))&&(z&&D(22,"max denominator "+(p?"out of range":"not an integer"),t),t=!p&&u.c&&S(u,u.e+1,1).gte(H)?u:null)),!m)return h.toString();for(l=o(m),a=d.e=l.length-h.e-1,d.c[0]=N[(s=a%I)<0?I+s:s],t=!t||u.cmp(d)>0?a>0?d:g:u,s=M,M=1/0,u=new e(l),c.c[0]=0;f=E(u,d,0,1),i=r.plus(f.times(y)),1!=i.cmp(t);)r=y,y=i,g=c.plus(f.times(i=g)),c=i,d=u.minus(f.times(i=d)),u=i;return i=E(t.minus(r),y,0,1),c=c.plus(i.times(g)),r=r.plus(i.times(y)),c.s=g.s=h.s,a*=2,n=E(g,y,a,j).minus(h).abs().cmp(E(c,r,a,j).minus(h).abs())<1?[g.toString(),y.toString()]:[c.toString(),r.toString()],M=s,n},R.toNumber=function(){var t=this;return+t||(t.s?0*t.s:0/0)},R.toPower=R.pow=function(t){var n,r,i=v(0>t?-t:+t),o=this;if(!W(t,-B,B,23,"exponent")&&(!isFinite(t)||i>B&&(t/=0)||parseFloat(t)!=t&&!(t=0/0)))return new e(Math.pow(+o,t));for(n=V?y(V/I+2):0,r=new e(H);;){if(i%2){if(r=r.times(o),!r.c)break;n&&r.c.length>n&&(r.c.length=n)}if(i=v(i/2),!i)break;o=o.times(o),n&&o.c&&o.c.length>n&&(o.c.length=n)}return 0>t&&(r=H.div(r)),n?S(r,V,j):r},R.toPrecision=function(t,e){return h(this,null!=t&&W(t,1,A,24,"precision")?0|t:null,e,24)},R.toString=function(t){var e,r=this,i=r.s,a=r.e;return null===a?i?(e="Infinity",0>i&&(e="-"+e)):e="NaN":(e=o(r.c),e=null!=t&&W(t,2,64,25,"base")?n(l(e,a),0|t,10,i):q>=a||a>=U?f(e,a):l(e,a),0>i&&r.c[0]&&(e="-"+e)),e},R.truncated=R.trunc=function(){return S(new e(this),this.e+1,1)},R.valueOf=R.toJSON=function(){return this.toString()},null!=t&&e.config(t),e}function i(t){var e=0|t;return t>0||t===e?e:e-1}function o(t){for(var e,n,r=1,i=t.length,o=t[0]+"";i>r;){for(e=t[r++]+"",n=I-e.length;n--;e="0"+e);o+=e}for(i=o.length;48===o.charCodeAt(--i););return o.slice(0,i+1||1)}function a(t,e){var n,r,i=t.c,o=e.c,a=t.s,s=e.s,u=t.e,c=e.e;if(!a||!s)return null;if(n=i&&!i[0],r=o&&!o[0],n||r)return n?r?0:-s:a;if(a!=s)return a;if(n=0>a,r=u==c,!i||!o)return r?0:!i^n?1:-1;if(!r)return u>c^n?1:-1;for(s=(u=i.length)<(c=o.length)?u:c,a=0;s>a;a++)if(i[a]!=o[a])return i[a]>o[a]^n?1:-1;return u==c?0:u>c^n?1:-1}function s(t,e,n){return(t=p(t))>=e&&n>=t}function u(t){return"[object Array]"==Object.prototype.toString.call(t)}function c(t,e,n){for(var r,i,o=[0],a=0,s=t.length;s>a;){for(i=o.length;i--;o[i]*=e);for(o[r=0]+=x.indexOf(t.charAt(a++));rn-1&&(null==o[r+1]&&(o[r+1]=0),o[r+1]+=o[r]/n|0,o[r]%=n)}return o.reverse()}function f(t,e){return(t.length>1?t.charAt(0)+"."+t.slice(1):t)+(0>e?"e":"e+")+e}function l(t,e){var n,r;if(0>e){for(r="0.";++e;r+="0");t=r+t}else if(n=t.length,++e>n){for(r="0",e-=n;--e;r+="0");t+=r}else n>e&&(t=t.slice(0,e)+"."+t.slice(e));return t}function p(t){return t=parseFloat(t),0>t?y(t):v(t)}var h,m,d,g=/^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,y=Math.ceil,v=Math.floor,w=" not a boolean or binary digit",b="rounding mode",_="number type has more than 15 significant digits",x="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_",F=1e14,I=14,B=9007199254740991,N=[1,10,100,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,1e11,1e12,1e13],O=1e7,A=1e9;if(h=r(),"function"==typeof define&&define.amd)define(function(){return h});else if("undefined"!=typeof e&&e.exports){if(e.exports=h,!m)try{m=t("crypto")}catch(k){}}else n.BigNumber=h}(this)},{crypto:31}],web3:[function(t,e,n){var r=t("./lib/web3");r.providers.HttpProvider=t("./lib/web3/httpprovider"),r.providers.QtSyncProvider=t("./lib/web3/qtsync"),r.eth.contract=t("./lib/web3/contract"),r.eth.namereg=t("./lib/web3/namereg"),r.eth.sendIBANTransaction=t("./lib/web3/transfer"),"undefined"!=typeof window&&"undefined"==typeof window.web3&&(window.web3=r),e.exports=r},{"./lib/web3":9,"./lib/web3/contract":11,"./lib/web3/httpprovider":19,"./lib/web3/namereg":23,"./lib/web3/qtsync":26,"./lib/web3/transfer":29}]},{},["web3"]); \ No newline at end of file +require=function t(e,n,r){function i(a,s){if(!n[a]){if(!e[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(o)return o(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return i(n?n:t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var o="function"==typeof require&&require,a=0;ao;o+=64)n.push(this._outputFormatter(new a(t.dynamicPart().substr(o+64,64))));return n}return this._outputFormatter(t)},u.prototype.sliceParam=function(t,e,n){return"bytes"===this._mode?a.decodeBytes(t,e):s(n)?a.decodeArray(t,e):a.decodeParam(t,e)};var c=function(t){this._types=t};c.prototype._requireType=function(t){var e=this._types.filter(function(e){return e.isType(t)})[0];if(!e)throw Error("invalid solidity type!: "+t);return e},c.prototype._formatInput=function(t,e){return this._requireType(t).formatInput(e,s(t))},c.prototype.encodeParam=function(t,e){return this._formatInput(t,e).encode()},c.prototype.encodeParams=function(t,e){var n=this,r=t.map(function(t,r){return n._formatInput(t,e[r])});return a.encodeList(r)},c.prototype.decodeParam=function(t,e){return this.decodeParams([t],e)[0]},c.prototype.decodeParams=function(t,e){var n=this;return t.map(function(t,r){var i=n._requireType(t),o=i.sliceParam(e,r,t);return i.formatOutput(o,s(t))})};var l=new c([new u({name:"address",match:"strict",mode:"value",inputFormatter:o.formatInputInt,outputFormatter:o.formatOutputAddress}),new u({name:"bool",match:"strict",mode:"value",inputFormatter:o.formatInputBool,outputFormatter:o.formatOutputBool}),new u({name:"int",match:"prefix",mode:"value",inputFormatter:o.formatInputInt,outputFormatter:o.formatOutputInt}),new u({name:"uint",match:"prefix",mode:"value",inputFormatter:o.formatInputInt,outputFormatter:o.formatOutputUInt}),new u({name:"bytes",match:"strict",mode:"bytes",inputFormatter:o.formatInputDynamicBytes,outputFormatter:o.formatOutputDynamicBytes}),new u({name:"bytes",match:"prefix",mode:"value",inputFormatter:o.formatInputBytes,outputFormatter:o.formatOutputBytes}),new u({name:"real",match:"prefix",mode:"value",inputFormatter:o.formatInputReal,outputFormatter:o.formatOutputReal}),new u({name:"ureal",match:"prefix",mode:"value",inputFormatter:o.formatInputReal,outputFormatter:o.formatOutputUReal})]);e.exports=l},{"../utils/utils":7,"./formatters":2,"./param":3,"bignumber.js":"bignumber.js"}],2:[function(t,e,n){var r=t("bignumber.js"),i=t("../utils/utils"),o=t("../utils/config"),a=t("./param"),s=function(t){var e=2*o.ETH_PADDING;r.config(o.ETH_BIGNUMBER_ROUNDING_MODE);var n=i.padLeft(i.toTwosComplement(t).round().toString(16),e);return new a(n)},u=function(t){var e=i.fromAscii(t,o.ETH_PADDING).substr(2);return new a(e)},c=function(t){var e=i.fromAscii(t,o.ETH_PADDING).substr(2);return new a(s(t.length).value+e,32)},l=function(t){var e="000000000000000000000000000000000000000000000000000000000000000"+(t?"1":"0");return new a(e)},f=function(t){return s(new r(t).times(new r(2).pow(128)))},p=function(t){return"1"===new r(t.substr(0,1),16).toString(2).substr(0,1)},h=function(t){var e=t.staticPart()||"0";return p(e)?new r(e,16).minus(new r("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",16)).minus(1):new r(e,16)},m=function(t){var e=t.staticPart()||"0";return new r(e,16)},d=function(t){return h(t).dividedBy(new r(2).pow(128))},g=function(t){return m(t).dividedBy(new r(2).pow(128))},y=function(t){return"0000000000000000000000000000000000000000000000000000000000000001"===t.staticPart()?!0:!1},v=function(t){return i.toAscii(t.staticPart())},w=function(t){return i.toAscii(t.dynamicPart().slice(64))},b=function(t){var e=t.staticPart();return"0x"+e.slice(e.length-40,e.length)};e.exports={formatInputInt:s,formatInputBytes:u,formatInputDynamicBytes:c,formatInputBool:l,formatInputReal:f,formatOutputInt:h,formatOutputUInt:m,formatOutputReal:d,formatOutputUReal:g,formatOutputBool:y,formatOutputBytes:v,formatOutputDynamicBytes:w,formatOutputAddress:b}},{"../utils/config":5,"../utils/utils":7,"./param":3,"bignumber.js":"bignumber.js"}],3:[function(t,e,n){var r=t("../utils/utils"),i=function(t,e){this.value=t||"",this.offset=e};i.prototype.dynamicPartLength=function(){return this.dynamicPart().length/2},i.prototype.withOffset=function(t){return new i(this.value,t)},i.prototype.combine=function(t){return new i(this.value+t.value)},i.prototype.isDynamic=function(){return this.value.length>64||void 0!==this.offset},i.prototype.offsetAsBytes=function(){return this.isDynamic()?r.padLeft(r.toTwosComplement(this.offset).toString(16),64):""},i.prototype.staticPart=function(){return this.isDynamic()?this.offsetAsBytes():this.value},i.prototype.dynamicPart=function(){return this.isDynamic()?this.value:""},i.prototype.encode=function(){return this.staticPart()+this.dynamicPart()},i.encodeList=function(t){var e=32*t.length,n=t.map(function(t){if(!t.isDynamic())return t;var n=e;return e+=t.dynamicPartLength(),t.withOffset(n)});return n.reduce(function(t,e){return t+e.dynamicPart()},n.reduce(function(t,e){return t+e.staticPart()},""))},i.decodeParam=function(t,e){return e=e||0,new i(t.substr(64*e,64))};var o=function(t,e){return parseInt("0x"+t.substr(64*e,64))};i.decodeBytes=function(t,e){e=e||0;var n=o(t,e);return new i(t.substr(2*n,128),0)},i.decodeArray=function(t,e){e=e||0;var n=o(t,e),r=parseInt("0x"+t.substr(2*n,64));return new i(t.substr(2*n,64*(r+1)),0)},e.exports=i},{"../utils/utils":7}],4:[function(t,e,n){"use strict";n.XMLHttpRequest="undefined"==typeof XMLHttpRequest?{}:XMLHttpRequest},{}],5:[function(t,e,n){var r=t("bignumber.js"),i=["wei","kwei","Mwei","Gwei","szabo","finney","femtoether","picoether","nanoether","microether","milliether","nano","micro","milli","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:i,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:r.ROUND_DOWN},ETH_POLLING_TIMEOUT:1e3,defaultBlock:"latest",defaultAccount:void 0}},{"bignumber.js":"bignumber.js"}],6:[function(t,e,n){var r=t("./utils"),i=t("crypto-js/sha3");e.exports=function(t,e){return"0x"!==t.substr(0,2)||e||(console.warn("requirement of using web3.fromAscii before sha3 is deprecated"),console.warn("new usage: 'web3.sha3(\"hello\")'"),console.warn("see https://github.com/ethereum/web3.js/pull/205"),console.warn("if you need to hash hex value, you can do 'sha3(\"0xfff\", true)'"),t=r.toAscii(t)),i(t,{outputLength:256}).toString()}},{"./utils":7,"crypto-js/sha3":33}],7:[function(t,e,n){var r=t("bignumber.js"),i={wei:"1",kwei:"1000",ada:"1000",femtoether:"1000",mwei:"1000000",babbage:"1000000",picoether:"1000000",gwei:"1000000000",shannon:"1000000000",nanoether:"1000000000",nano:"1000000000",szabo:"1000000000000",microether:"1000000000000",micro:"1000000000000",finney:"1000000000000000",milliether:"1000000000000000",milli:"1000000000000000",ether:"1000000000000000000",kether:"1000000000000000000000",grand:"1000000000000000000000",einstein:"1000000000000000000000",mether:"1000000000000000000000000",gether:"1000000000000000000000000000",tether:"1000000000000000000000000000000"},o=function(t,e,n){return new Array(e-t.length+1).join(n?n:"0")+t},a=function(t){var e="",n=0,r=t.length;for("0x"===t.substring(0,2)&&(n=2);r>n;n+=2){var i=parseInt(t.substr(n,2),16);if(0===i)break;e+=String.fromCharCode(i)}return e},s=function(t){for(var e="",n=0;nthis._inputTypes.length&&o.isObject(t[t.length-1])&&(e=t[t.length-1]),e.to=this._address,e.data="0x"+this.signature()+i.encodeParams(this._inputTypes,t),e},s.prototype.signature=function(){return a(this._name).slice(0,8)},s.prototype.unpackOutput=function(t){if(t){t=t.length>=2?t.slice(2):t;var e=i.decodeParams(this._outputTypes,t);return 1===e.length?e[0]:e}},s.prototype.call=function(){var t=Array.prototype.slice.call(arguments).filter(function(t){return void 0!==t}),e=this.extractCallback(t),n=this.toPayload(t);if(!e){var i=r.eth.call(n);return this.unpackOutput(i)}var o=this;r.eth.call(n,function(t,n){e(t,o.unpackOutput(n))})},s.prototype.sendTransaction=function(){var t=Array.prototype.slice.call(arguments).filter(function(t){return void 0!==t}),e=this.extractCallback(t),n=this.toPayload(t);return e?void r.eth.sendTransaction(n,e):r.eth.sendTransaction(n)},s.prototype.estimateGas=function(){var t=Array.prototype.slice.call(arguments),e=this.extractCallback(t),n=this.toPayload(t);return e?void r.eth.estimateGas(n,e):r.eth.estimateGas(n)},s.prototype.displayName=function(){return o.extractDisplayName(this._name)},s.prototype.typeName=function(){return o.extractTypeName(this._name)},s.prototype.request=function(){var t=Array.prototype.slice.call(arguments),e=this.extractCallback(t),n=this.toPayload(t),r=this.unpackOutput.bind(this);return{callback:e,payload:n,format:r}},s.prototype.execute=function(){var t=!this._constant;return t?this.sendTransaction.apply(this,Array.prototype.slice.call(arguments)):this.call.apply(this,Array.prototype.slice.call(arguments))},s.prototype.attachToContract=function(t){var e=this.execute.bind(this);e.request=this.request.bind(this),e.call=this.call.bind(this),e.sendTransaction=this.sendTransaction.bind(this),e.estimateGas=this.estimateGas.bind(this);var n=this.displayName();t[n]||(t[n]=e),t[n][this.typeName()]=e},e.exports=s},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9}],19:[function(t,e,n){"use strict";var r=t("xmlhttprequest").XMLHttpRequest,i=t("./errors"),o=function(t){this.host=t||"http://localhost:8545"};o.prototype.send=function(t){var e=new r;e.open("POST",this.host,!1);try{e.send(JSON.stringify(t))}catch(n){throw i.InvalidConnection(this.host)}var o=e.responseText;try{o=JSON.parse(o)}catch(a){throw i.InvalidResponse(o)}return o},o.prototype.sendAsync=function(t,e){var n=new r;n.onreadystatechange=function(){if(4===n.readyState){var t=n.responseText,r=null;try{t=JSON.parse(t)}catch(o){r=i.InvalidResponse(t)}e(r,t)}},n.open("POST",this.host,!0);try{n.send(JSON.stringify(t))}catch(o){e(i.InvalidConnection(this.host))}},e.exports=o},{"./errors":13,xmlhttprequest:4}],20:[function(t,e,n){var r=t("../utils/utils"),i=function(t){this._iban=t};i.prototype.isValid=function(){return r.isIBAN(this._iban)},i.prototype.isDirect=function(){return 34===this._iban.length},i.prototype.isIndirect=function(){return 20===this._iban.length},i.prototype.checksum=function(){return this._iban.substr(2,2)},i.prototype.institution=function(){return this.isIndirect()?this._iban.substr(7,4):""},i.prototype.client=function(){return this.isIndirect()?this._iban.substr(11):""},i.prototype.address=function(){return this.isDirect()?this._iban.substr(4):""},e.exports=i},{"../utils/utils":7}],21:[function(t,e,n){var r=function(){return arguments.callee._singletonInstance?arguments.callee._singletonInstance:(arguments.callee._singletonInstance=this,void(this.messageId=1))};r.getInstance=function(){var t=new r;return t},r.prototype.toPayload=function(t,e){return t||console.error("jsonrpc method should be specified!"),{jsonrpc:"2.0",method:t,params:e||[],id:this.messageId++}},r.prototype.isValidResponse=function(t){return!!t&&!t.error&&"2.0"===t.jsonrpc&&"number"==typeof t.id&&void 0!==t.result},r.prototype.toBatchPayload=function(t){var e=this;return t.map(function(t){return e.toPayload(t.method,t.params)})},e.exports=r},{}],22:[function(t,e,n){var r=t("./requestmanager"),i=t("../utils/utils"),o=t("./errors"),a=function(t){this.name=t.name,this.call=t.call,this.params=t.params||0,this.inputFormatter=t.inputFormatter,this.outputFormatter=t.outputFormatter};a.prototype.getCall=function(t){return i.isFunction(this.call)?this.call(t):this.call},a.prototype.extractCallback=function(t){return i.isFunction(t[t.length-1])?t.pop():void 0},a.prototype.validateArgs=function(t){if(t.length!==this.params)throw o.InvalidNumberOfParams()},a.prototype.formatInput=function(t){return this.inputFormatter?this.inputFormatter.map(function(e,n){return e?e(t[n]):t[n]}):t},a.prototype.formatOutput=function(t){return this.outputFormatter&&null!==t?this.outputFormatter(t):t},a.prototype.attachToObject=function(t){var e=this.send.bind(this);e.request=this.request.bind(this),e.call=this.call;var n=this.name.split(".");n.length>1?(t[n[0]]=t[n[0]]||{},t[n[0]][n[1]]=e):t[n[0]]=e},a.prototype.toPayload=function(t){var e=this.getCall(t),n=this.extractCallback(t),r=this.formatInput(t);return this.validateArgs(r),{method:e,params:r,callback:n}},a.prototype.request=function(){var t=this.toPayload(Array.prototype.slice.call(arguments));return t.format=this.formatOutput.bind(this),t},a.prototype.send=function(){var t=this.toPayload(Array.prototype.slice.call(arguments));if(t.callback){var e=this;return r.getInstance().sendAsync(t,function(n,r){t.callback(n,e.formatOutput(r))})}return this.formatOutput(r.getInstance().send(t))},e.exports=a},{"../utils/utils":7,"./errors":13,"./requestmanager":27}],23:[function(t,e,n){var r=t("./contract"),i="0xc6d9d2cd449a754c494264e1809c50e34d64562b",o=[{constant:!0,inputs:[{name:"_owner",type:"address"}],name:"name",outputs:[{name:"o_name",type:"bytes32"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"owner",outputs:[{name:"",type:"address"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"content",outputs:[{name:"",type:"bytes32"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"addr",outputs:[{name:"",type:"address"}],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"}],name:"reserve",outputs:[],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"subRegistrar",outputs:[{name:"o_subRegistrar",type:"address"}],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_newOwner",type:"address"}],name:"transfer",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_registrar",type:"address"}],name:"setSubRegistrar",outputs:[],type:"function"},{constant:!1,inputs:[],name:"Registrar",outputs:[],type:"function"},{constant:!1, +inputs:[{name:"_name",type:"bytes32"},{name:"_a",type:"address"},{name:"_primary",type:"bool"}],name:"setAddress",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_content",type:"bytes32"}],name:"setContent",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"}],name:"disown",outputs:[],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"register",outputs:[{name:"",type:"address"}],type:"function"},{anonymous:!1,inputs:[{indexed:!0,name:"name",type:"bytes32"}],name:"Changed",type:"event"},{anonymous:!1,inputs:[{indexed:!0,name:"name",type:"bytes32"},{indexed:!0,name:"addr",type:"address"}],name:"PrimaryChanged",type:"event"}];e.exports=r(o).at(i)},{"./contract":11}],24:[function(t,e,n){var r=t("../utils/utils"),i=t("./property"),o=[],a=[new i({name:"listening",getter:"net_listening"}),new i({name:"peerCount",getter:"net_peerCount",outputFormatter:r.toDecimal})];e.exports={methods:o,properties:a}},{"../utils/utils":7,"./property":25}],25:[function(t,e,n){var r=t("./requestmanager"),i=function(t){this.name=t.name,this.getter=t.getter,this.setter=t.setter,this.outputFormatter=t.outputFormatter,this.inputFormatter=t.inputFormatter};i.prototype.formatInput=function(t){return this.inputFormatter?this.inputFormatter(t):t},i.prototype.formatOutput=function(t){return this.outputFormatter&&null!==t?this.outputFormatter(t):t},i.prototype.attachToObject=function(t){var e={get:this.get.bind(this)},n=this.name.split("."),r=n[0];n.length>1&&(t[n[0]]=t[n[0]]||{},t=t[n[0]],r=n[1]),Object.defineProperty(t,r,e);var i=function(t,e){return t+e.charAt(0).toUpperCase()+e.slice(1)};t[i("get",r)]=this.getAsync.bind(this)},i.prototype.get=function(){return this.formatOutput(r.getInstance().send({method:this.getter}))},i.prototype.getAsync=function(t){var e=this;r.getInstance().sendAsync({method:this.getter},function(n,r){return n?t(n):void t(n,e.formatOutput(r))})},e.exports=i},{"./requestmanager":27}],26:[function(t,e,n){var r=function(){};r.prototype.send=function(t){var e=navigator.qt.callMethod(JSON.stringify(t));return JSON.parse(e)},e.exports=r},{}],27:[function(t,e,n){var r=t("./jsonrpc"),i=t("../utils/utils"),o=t("../utils/config"),a=t("./errors"),s=function(t){return arguments.callee._singletonInstance?arguments.callee._singletonInstance:(arguments.callee._singletonInstance=this,this.provider=t,this.polls=[],this.timeout=null,void this.poll())};s.getInstance=function(){var t=new s;return t},s.prototype.send=function(t){if(!this.provider)return console.error(a.InvalidProvider()),null;var e=r.getInstance().toPayload(t.method,t.params),n=this.provider.send(e);if(!r.getInstance().isValidResponse(n))throw a.InvalidResponse(n);return n.result},s.prototype.sendAsync=function(t,e){if(!this.provider)return e(a.InvalidProvider());var n=r.getInstance().toPayload(t.method,t.params);this.provider.sendAsync(n,function(t,n){return t?e(t):r.getInstance().isValidResponse(n)?void e(null,n.result):e(a.InvalidResponse(n))})},s.prototype.sendBatch=function(t,e){if(!this.provider)return e(a.InvalidProvider());var n=r.getInstance().toBatchPayload(t);this.provider.sendAsync(n,function(t,n){return t?e(t):i.isArray(n)?void e(t,n):e(a.InvalidResponse(n))})},s.prototype.setProvider=function(t){this.provider=t},s.prototype.startPolling=function(t,e,n,r){this.polls.push({data:t,id:e,callback:n,uninstall:r})},s.prototype.stopPolling=function(t){for(var e=this.polls.length;e--;){var n=this.polls[e];n.id===t&&this.polls.splice(e,1)}},s.prototype.reset=function(){this.polls.forEach(function(t){t.uninstall(t.id)}),this.polls=[],this.timeout&&(clearTimeout(this.timeout),this.timeout=null),this.poll()},s.prototype.poll=function(){if(this.timeout=setTimeout(this.poll.bind(this),o.ETH_POLLING_TIMEOUT),this.polls.length){if(!this.provider)return void console.error(a.InvalidProvider());var t=r.getInstance().toBatchPayload(this.polls.map(function(t){return t.data})),e=this;this.provider.sendAsync(t,function(t,n){if(!t){if(!i.isArray(n))throw a.InvalidResponse(n);n.map(function(t,n){return t.callback=e.polls[n].callback,t}).filter(function(t){var e=r.getInstance().isValidResponse(t);return e||t.callback(a.InvalidResponse(t)),e}).filter(function(t){return i.isArray(t.result)&&t.result.length>0}).forEach(function(t){t.callback(null,t.result)})}})}},e.exports=s},{"../utils/config":5,"../utils/utils":7,"./errors":13,"./jsonrpc":21}],28:[function(t,e,n){var r=t("./method"),i=t("./formatters"),o=new r({name:"post",call:"shh_post",params:1,inputFormatter:[i.inputPostFormatter]}),a=new r({name:"newIdentity",call:"shh_newIdentity",params:0}),s=new r({name:"hasIdentity",call:"shh_hasIdentity",params:1}),u=new r({name:"newGroup",call:"shh_newGroup",params:0}),c=new r({name:"addToGroup",call:"shh_addToGroup",params:0}),l=[o,a,s,u,c];e.exports={methods:l}},{"./formatters":17,"./method":22}],29:[function(t,e,n){var r=t("../web3"),i=t("./icap"),o=t("./namereg"),a=t("./contract"),s=function(t,e,n,r){var a=new i(e);if(!a.isValid())throw new Error("invalid iban address");if(a.isDirect())return u(t,a.address(),n,r);if(!r){var s=o.addr(a.institution());return c(t,s,n,a.client())}o.addr(a.insitution(),function(e,i){return c(t,i,n,a.client(),r)})},u=function(t,e,n,i){return r.eth.sendTransaction({address:e,from:t,value:n},i)},c=function(t,e,n,r,i){var o=[{constant:!1,inputs:[{name:"name",type:"bytes32"}],name:"deposit",outputs:[],type:"function"}];return a(o).at(e).deposit(r,{from:t,value:n},i)};e.exports=s},{"../web3":9,"./contract":11,"./icap":20,"./namereg":23}],30:[function(t,e,n){var r=t("./method"),i=function(){var t=function(t){var e=t[0];switch(e){case"latest":return t.pop(),this.params=0,"eth_newBlockFilter";case"pending":return t.pop(),this.params=0,"eth_newPendingTransactionFilter";default:return"eth_newFilter"}},e=new r({name:"newFilter",call:t,params:1}),n=new r({name:"uninstallFilter",call:"eth_uninstallFilter",params:1}),i=new r({name:"getLogs",call:"eth_getFilterLogs",params:1}),o=new r({name:"poll",call:"eth_getFilterChanges",params:1});return[e,n,i,o]},o=function(){var t=new r({name:"newFilter",call:"shh_newFilter",params:1}),e=new r({name:"uninstallFilter",call:"shh_uninstallFilter",params:1}),n=new r({name:"getLogs",call:"shh_getMessages",params:1}),i=new r({name:"poll",call:"shh_getFilterChanges",params:1});return[t,e,n,i]};e.exports={eth:i,shh:o}},{"./method":22}],31:[function(t,e,n){},{}],32:[function(t,e,n){!function(t,r){"object"==typeof n?e.exports=n=r():"function"==typeof define&&define.amd?define([],r):t.CryptoJS=r()}(this,function(){var t=t||function(t,e){var n={},r=n.lib={},i=r.Base=function(){function t(){}return{extend:function(e){t.prototype=this;var n=new t;return e&&n.mixIn(e),n.hasOwnProperty("init")||(n.init=function(){n.$super.init.apply(this,arguments)}),n.init.prototype=n,n.$super=this,n},create:function(){var t=this.extend();return t.init.apply(t,arguments),t},init:function(){},mixIn:function(t){for(var e in t)t.hasOwnProperty(e)&&(this[e]=t[e]);t.hasOwnProperty("toString")&&(this.toString=t.toString)},clone:function(){return this.init.prototype.extend(this)}}}(),o=r.WordArray=i.extend({init:function(t,n){t=this.words=t||[],this.sigBytes=n!=e?n:4*t.length},toString:function(t){return(t||s).stringify(this)},concat:function(t){var e=this.words,n=t.words,r=this.sigBytes,i=t.sigBytes;if(this.clamp(),r%4)for(var o=0;i>o;o++){var a=n[o>>>2]>>>24-o%4*8&255;e[r+o>>>2]|=a<<24-(r+o)%4*8}else for(var o=0;i>o;o+=4)e[r+o>>>2]=n[o>>>2];return this.sigBytes+=i,this},clamp:function(){var e=this.words,n=this.sigBytes;e[n>>>2]&=4294967295<<32-n%4*8,e.length=t.ceil(n/4)},clone:function(){var t=i.clone.call(this);return t.words=this.words.slice(0),t},random:function(e){for(var n,r=[],i=function(e){var e=e,n=987654321,r=4294967295;return function(){n=36969*(65535&n)+(n>>16)&r,e=18e3*(65535&e)+(e>>16)&r;var i=(n<<16)+e&r;return i/=4294967296,i+=.5,i*(t.random()>.5?1:-1)}},a=0;e>a;a+=4){var s=i(4294967296*(n||t.random()));n=987654071*s(),r.push(4294967296*s()|0)}return new o.init(r,e)}}),a=n.enc={},s=a.Hex={stringify:function(t){for(var e=t.words,n=t.sigBytes,r=[],i=0;n>i;i++){var o=e[i>>>2]>>>24-i%4*8&255;r.push((o>>>4).toString(16)),r.push((15&o).toString(16))}return r.join("")},parse:function(t){for(var e=t.length,n=[],r=0;e>r;r+=2)n[r>>>3]|=parseInt(t.substr(r,2),16)<<24-r%8*4;return new o.init(n,e/2)}},u=a.Latin1={stringify:function(t){for(var e=t.words,n=t.sigBytes,r=[],i=0;n>i;i++){var o=e[i>>>2]>>>24-i%4*8&255;r.push(String.fromCharCode(o))}return r.join("")},parse:function(t){for(var e=t.length,n=[],r=0;e>r;r++)n[r>>>2]|=(255&t.charCodeAt(r))<<24-r%4*8;return new o.init(n,e)}},c=a.Utf8={stringify:function(t){try{return decodeURIComponent(escape(u.stringify(t)))}catch(e){throw new Error("Malformed UTF-8 data")}},parse:function(t){return u.parse(unescape(encodeURIComponent(t)))}},l=r.BufferedBlockAlgorithm=i.extend({reset:function(){this._data=new o.init,this._nDataBytes=0},_append:function(t){"string"==typeof t&&(t=c.parse(t)),this._data.concat(t),this._nDataBytes+=t.sigBytes},_process:function(e){var n=this._data,r=n.words,i=n.sigBytes,a=this.blockSize,s=4*a,u=i/s;u=e?t.ceil(u):t.max((0|u)-this._minBufferSize,0);var c=u*a,l=t.min(4*c,i);if(c){for(var f=0;c>f;f+=a)this._doProcessBlock(r,f);var p=r.splice(0,c);n.sigBytes-=l}return new o.init(p,l)},clone:function(){var t=i.clone.call(this);return t._data=this._data.clone(),t},_minBufferSize:0}),f=(r.Hasher=l.extend({cfg:i.extend(),init:function(t){this.cfg=this.cfg.extend(t),this.reset()},reset:function(){l.reset.call(this),this._doReset()},update:function(t){return this._append(t),this._process(),this},finalize:function(t){t&&this._append(t);var e=this._doFinalize();return e},blockSize:16,_createHelper:function(t){return function(e,n){return new t.init(n).finalize(e)}},_createHmacHelper:function(t){return function(e,n){return new f.HMAC.init(t,n).finalize(e)}}}),n.algo={});return n}(Math);return t})},{}],33:[function(t,e,n){!function(r,i,o){"object"==typeof n?e.exports=n=i(t("./core"),t("./x64-core")):"function"==typeof define&&define.amd?define(["./core","./x64-core"],i):i(r.CryptoJS)}(this,function(t){return function(e){var n=t,r=n.lib,i=r.WordArray,o=r.Hasher,a=n.x64,s=a.Word,u=n.algo,c=[],l=[],f=[];!function(){for(var t=1,e=0,n=0;24>n;n++){c[t+5*e]=(n+1)*(n+2)/2%64;var r=e%5,i=(2*t+3*e)%5;t=r,e=i}for(var t=0;5>t;t++)for(var e=0;5>e;e++)l[t+5*e]=e+(2*t+3*e)%5*5;for(var o=1,a=0;24>a;a++){for(var u=0,p=0,h=0;7>h;h++){if(1&o){var m=(1<m?p^=1<t;t++)p[t]=s.create()}();var h=u.SHA3=o.extend({cfg:o.cfg.extend({outputLength:512}),_doReset:function(){for(var t=this._state=[],e=0;25>e;e++)t[e]=new s.init;this.blockSize=(1600-2*this.cfg.outputLength)/32},_doProcessBlock:function(t,e){for(var n=this._state,r=this.blockSize/2,i=0;r>i;i++){var o=t[e+2*i],a=t[e+2*i+1];o=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8),a=16711935&(a<<8|a>>>24)|4278255360&(a<<24|a>>>8);var s=n[i];s.high^=a,s.low^=o}for(var u=0;24>u;u++){for(var h=0;5>h;h++){for(var m=0,d=0,g=0;5>g;g++){var s=n[h+5*g];m^=s.high,d^=s.low}var y=p[h];y.high=m,y.low=d}for(var h=0;5>h;h++)for(var v=p[(h+4)%5],w=p[(h+1)%5],b=w.high,_=w.low,m=v.high^(b<<1|_>>>31),d=v.low^(_<<1|b>>>31),g=0;5>g;g++){var s=n[h+5*g];s.high^=m,s.low^=d}for(var x=1;25>x;x++){var s=n[x],F=s.high,I=s.low,B=c[x];if(32>B)var m=F<>>32-B,d=I<>>32-B;else var m=I<>>64-B,d=F<>>64-B;var N=p[l[x]];N.high=m,N.low=d}var O=p[0],A=n[0];O.high=A.high,O.low=A.low;for(var h=0;5>h;h++)for(var g=0;5>g;g++){var x=h+5*g,s=n[x],k=p[x],P=p[(h+1)%5+5*g],T=p[(h+2)%5+5*g];s.high=k.high^~P.high&T.high,s.low=k.low^~P.low&T.low}var s=n[0],D=f[u];s.high^=D.high,s.low^=D.low}},_doFinalize:function(){var t=this._data,n=t.words,r=(8*this._nDataBytes,8*t.sigBytes),o=32*this.blockSize;n[r>>>5]|=1<<24-r%32,n[(e.ceil((r+1)/o)*o>>>5)-1]|=128,t.sigBytes=4*n.length,this._process();for(var a=this._state,s=this.cfg.outputLength/8,u=s/8,c=[],l=0;u>l;l++){var f=a[l],p=f.high,h=f.low;p=16711935&(p<<8|p>>>24)|4278255360&(p<<24|p>>>8),h=16711935&(h<<8|h>>>24)|4278255360&(h<<24|h>>>8),c.push(h),c.push(p)}return new i.init(c,s)},clone:function(){for(var t=o.clone.call(this),e=t._state=this._state.slice(0),n=0;25>n;n++)e[n]=e[n].clone();return t}});n.SHA3=o._createHelper(h),n.HmacSHA3=o._createHmacHelper(h)}(Math),t.SHA3})},{"./core":32,"./x64-core":34}],34:[function(t,e,n){!function(r,i){"object"==typeof n?e.exports=n=i(t("./core")):"function"==typeof define&&define.amd?define(["./core"],i):i(r.CryptoJS)}(this,function(t){return function(e){{var n=t,r=n.lib,i=r.Base,o=r.WordArray,a=n.x64={};a.Word=i.extend({init:function(t,e){this.high=t,this.low=e}}),a.WordArray=i.extend({init:function(t,n){t=this.words=t||[],this.sigBytes=n!=e?n:8*t.length},toX32:function(){for(var t=this.words,e=t.length,n=[],r=0;e>r;r++){var i=t[r];n.push(i.high),n.push(i.low)}return o.create(n,this.sigBytes)},clone:function(){for(var t=i.clone.call(this),e=t.words=this.words.slice(0),n=e.length,r=0;n>r;r++)e[r]=e[r].clone();return t}})}}(),t})},{"./core":32}],"bignumber.js":[function(t,e,n){!function(n){"use strict";function r(t){function e(t,r){var i,o,a,s,u,c,l=this;if(!(l instanceof e))return z&&D(26,"constructor call without new",t),new e(t,r);if(null!=r&&W(r,2,64,C,"base")){if(r=0|r,c=t+"",10==r)return l=new e(t instanceof e?t:c),S(l,L+l.e+1,j);if((s="number"==typeof t)&&0*t!=0||!new RegExp("^-?"+(i="["+x.slice(0,r)+"]+")+"(?:\\."+i+")?$",37>r?"i":"").test(c))return d(l,c,s,r);s?(l.s=0>1/t?(c=c.slice(1),-1):1,z&&c.replace(/^0\.0*|\./,"").length>15&&D(C,_,t),s=!1):l.s=45===c.charCodeAt(0)?(c=c.slice(1),-1):1,c=n(c,10,r,l.s)}else{if(t instanceof e)return l.s=t.s,l.e=t.e,l.c=(t=t.c)?t.slice():t,void(C=0);if((s="number"==typeof t)&&0*t==0){if(l.s=0>1/t?(t=-t,-1):1,t===~~t){for(o=0,a=t;a>=10;a/=10,o++);return l.e=o,l.c=[t],void(C=0)}c=t+""}else{if(!g.test(c=t+""))return d(l,c,s);l.s=45===c.charCodeAt(0)?(c=c.slice(1),-1):1}}for((o=c.indexOf("."))>-1&&(c=c.replace(".","")),(a=c.search(/e/i))>0?(0>o&&(o=a),o+=+c.slice(a+1),c=c.substring(0,a)):0>o&&(o=c.length),a=0;48===c.charCodeAt(a);a++);for(u=c.length;48===c.charCodeAt(--u););if(c=c.slice(a,u+1))if(u=c.length,s&&z&&u>15&&D(C,_,l.s*t),o=o-a-1,o>M)l.c=l.e=null;else if(G>o)l.c=[l.e=0];else{if(l.e=o,l.c=[],a=(o+1)%I,0>o&&(a+=I),u>a){for(a&&l.c.push(+c.slice(0,a)),u-=I;u>a;)l.c.push(+c.slice(a,a+=I));c=c.slice(a),a=I-c.length}else a-=u;for(;a--;c+="0");l.c.push(+c)}else l.c=[l.e=0];C=0}function n(t,n,r,i){var a,s,u,l,p,h,m,d=t.indexOf("."),g=L,y=j;for(37>r&&(t=t.toLowerCase()),d>=0&&(u=V,V=0,t=t.replace(".",""),m=new e(r),p=m.pow(t.length-d),V=u,m.c=c(f(o(p.c),p.e),10,n),m.e=m.c.length),h=c(t,r,n),s=u=h.length;0==h[--u];h.pop());if(!h[0])return"0";if(0>d?--s:(p.c=h,p.e=s,p.s=i,p=E(p,m,g,y,n),h=p.c,l=p.r,s=p.e),a=s+g+1,d=h[a],u=n/2,l=l||0>a||null!=h[a+1],l=4>y?(null!=d||l)&&(0==y||y==(p.s<0?3:2)):d>u||d==u&&(4==y||l||6==y&&1&h[a-1]||y==(p.s<0?8:7)),1>a||!h[0])t=l?f("1",-g):"0";else{if(h.length=a,l)for(--n;++h[--a]>n;)h[a]=0,a||(++s,h.unshift(1));for(u=h.length;!h[--u];);for(d=0,t="";u>=d;t+=x.charAt(h[d++]));t=f(t,s)}return t}function h(t,n,r,i){var a,s,u,c,p;if(r=null!=r&&W(r,0,8,i,b)?0|r:j,!t.c)return t.toString();if(a=t.c[0],u=t.e,null==n)p=o(t.c),p=19==i||24==i&&q>=u?l(p,u):f(p,u);else if(t=S(new e(t),n,r),s=t.e,p=o(t.c),c=p.length,19==i||24==i&&(s>=n||q>=s)){for(;n>c;p+="0",c++);p=l(p,s)}else if(n-=u,p=f(p,s),s+1>c){if(--n>0)for(p+=".";n--;p+="0");}else if(n+=s-c,n>0)for(s+1==c&&(p+=".");n--;p+="0");return t.s<0&&a?"-"+p:p}function k(t,n){var r,i,o=0;for(u(t[0])&&(t=t[0]),r=new e(t[0]);++ot||t>n||t!=p(t))&&D(r,(i||"decimal places")+(e>t||t>n?" out of range":" not an integer"),t),!0}function T(t,e,n){for(var r=1,i=e.length;!e[--i];e.pop());for(i=e[0];i>=10;i/=10,r++);return(n=r+n*I-1)>M?t.c=t.e=null:G>n?t.c=[t.e=0]:(t.e=n,t.c=e),t}function D(t,e,n){var r=new Error(["new BigNumber","cmp","config","div","divToInt","eq","gt","gte","lt","lte","minus","mod","plus","precision","random","round","shift","times","toDigits","toExponential","toFixed","toFormat","toFraction","pow","toPrecision","toString","BigNumber"][t]+"() "+e+": "+n);throw r.name="BigNumber Error",C=0,r}function S(t,e,n,r){var i,o,a,s,u,c,l,f=t.c,p=N;if(f){t:{for(i=1,s=f[0];s>=10;s/=10,i++);if(o=e-i,0>o)o+=I,a=e,u=f[c=0],l=u/p[i-a-1]%10|0;else if(c=y((o+1)/I),c>=f.length){if(!r)break t;for(;f.length<=c;f.push(0));u=l=0,i=1,o%=I,a=o-I+1}else{for(u=s=f[c],i=1;s>=10;s/=10,i++);o%=I,a=o-I+i,l=0>a?0:u/p[i-a-1]%10|0}if(r=r||0>e||null!=f[c+1]||(0>a?u:u%p[i-a-1]),r=4>n?(l||r)&&(0==n||n==(t.s<0?3:2)):l>5||5==l&&(4==n||r||6==n&&(o>0?a>0?u/p[i-a]:0:f[c-1])%10&1||n==(t.s<0?8:7)),1>e||!f[0])return f.length=0,r?(e-=t.e+1,f[0]=p[e%I],t.e=-e||0):f[0]=t.e=0,t;if(0==o?(f.length=c,s=1,c--):(f.length=c+1,s=p[I-o],f[c]=a>0?v(u/p[i-a]%p[a])*s:0),r)for(;;){if(0==c){for(o=1,a=f[0];a>=10;a/=10,o++);for(a=f[0]+=s,s=1;a>=10;a/=10,s++);o!=s&&(t.e++,f[0]==F&&(f[0]=1));break}if(f[c]+=s,f[c]!=F)break;f[c--]=0,s=1}for(o=f.length;0===f[--o];f.pop());}t.e>M?t.c=t.e=null:t.en?null!=(t=i[n++]):void 0};return a(e="DECIMAL_PLACES")&&W(t,0,A,2,e)&&(L=0|t),r[e]=L,a(e="ROUNDING_MODE")&&W(t,0,8,2,e)&&(j=0|t),r[e]=j,a(e="EXPONENTIAL_AT")&&(u(t)?W(t[0],-A,0,2,e)&&W(t[1],0,A,2,e)&&(q=0|t[0],U=0|t[1]):W(t,-A,A,2,e)&&(q=-(U=0|(0>t?-t:t)))),r[e]=[q,U],a(e="RANGE")&&(u(t)?W(t[0],-A,-1,2,e)&&W(t[1],1,A,2,e)&&(G=0|t[0],M=0|t[1]):W(t,-A,A,2,e)&&(0|t?G=-(M=0|(0>t?-t:t)):z&&D(2,e+" cannot be zero",t))),r[e]=[G,M],a(e="ERRORS")&&(t===!!t||1===t||0===t?(C=0,W=(z=!!t)?P:s):z&&D(2,e+w,t)),r[e]=z,a(e="CRYPTO")&&(t===!!t||1===t||0===t?(J=!(!t||!m||"object"!=typeof m),t&&!J&&z&&D(2,"crypto unavailable",m)):z&&D(2,e+w,t)),r[e]=J,a(e="MODULO_MODE")&&W(t,0,9,2,e)&&($=0|t),r[e]=$,a(e="POW_PRECISION")&&W(t,0,A,2,e)&&(V=0|t),r[e]=V,a(e="FORMAT")&&("object"==typeof t?X=t:z&&D(2,e+" not an object",t)),r[e]=X,r},e.max=function(){return k(arguments,R.lt)},e.min=function(){return k(arguments,R.gt)},e.random=function(){var t=9007199254740992,n=Math.random()*t&2097151?function(){return v(Math.random()*t)}:function(){return 8388608*(1073741824*Math.random()|0)+(8388608*Math.random()|0)};return function(t){var r,i,o,a,s,u=0,c=[],l=new e(H);if(t=null!=t&&W(t,0,A,14)?0|t:L,a=y(t/I),J)if(m&&m.getRandomValues){for(r=m.getRandomValues(new Uint32Array(a*=2));a>u;)s=131072*r[u]+(r[u+1]>>>11),s>=9e15?(i=m.getRandomValues(new Uint32Array(2)),r[u]=i[0],r[u+1]=i[1]):(c.push(s%1e14),u+=2);u=a/2}else if(m&&m.randomBytes){for(r=m.randomBytes(a*=7);a>u;)s=281474976710656*(31&r[u])+1099511627776*r[u+1]+4294967296*r[u+2]+16777216*r[u+3]+(r[u+4]<<16)+(r[u+5]<<8)+r[u+6],s>=9e15?m.randomBytes(7).copy(r,u):(c.push(s%1e14),u+=7);u=a/7}else z&&D(14,"crypto unavailable",m);if(!u)for(;a>u;)s=n(),9e15>s&&(c[u++]=s%1e14);for(a=c[--u],t%=I,a&&t&&(s=N[I-t],c[u]=v(a/s)*s);0===c[u];c.pop(),u--);if(0>u)c=[o=0];else{for(o=-1;0===c[0];c.shift(),o-=I);for(u=1,s=c[0];s>=10;s/=10,u++);I>u&&(o-=I-u)}return l.e=o,l.c=c,l}}(),E=function(){function t(t,e,n){var r,i,o,a,s=0,u=t.length,c=e%O,l=e/O|0;for(t=t.slice();u--;)o=t[u]%O,a=t[u]/O|0,r=l*o+a*c,i=c*o+r%O*O+s,s=(i/n|0)+(r/O|0)+l*a,t[u]=i%n;return s&&t.unshift(s),t}function n(t,e,n,r){var i,o;if(n!=r)o=n>r?1:-1;else for(i=o=0;n>i;i++)if(t[i]!=e[i]){o=t[i]>e[i]?1:-1;break}return o}function r(t,e,n,r){for(var i=0;n--;)t[n]-=i,i=t[n]1;t.shift());}return function(o,a,s,u,c){var l,f,p,h,m,d,g,y,w,b,_,x,B,N,O,A,k,P=o.s==a.s?1:-1,T=o.c,D=a.c;if(!(T&&T[0]&&D&&D[0]))return new e(o.s&&a.s&&(T?!D||T[0]!=D[0]:D)?T&&0==T[0]||!D?0*P:P/0:0/0);for(y=new e(P),w=y.c=[],f=o.e-a.e,P=s+f+1,c||(c=F,f=i(o.e/I)-i(a.e/I),P=P/I|0),p=0;D[p]==(T[p]||0);p++);if(D[p]>(T[p]||0)&&f--,0>P)w.push(1),h=!0;else{for(N=T.length,A=D.length,p=0,P+=2,m=v(c/(D[0]+1)),m>1&&(D=t(D,m,c),T=t(T,m,c),A=D.length,N=T.length),B=A,b=T.slice(0,A),_=b.length;A>_;b[_++]=0);k=D.slice(),k.unshift(0),O=D[0],D[1]>=c/2&&O++;do{if(m=0,l=n(D,b,A,_),0>l){if(x=b[0],A!=_&&(x=x*c+(b[1]||0)),m=v(x/O),m>1)for(m>=c&&(m=c-1),d=t(D,m,c),g=d.length,_=b.length;1==n(d,b,g,_);)m--,r(d,g>A?k:D,g,c),g=d.length,l=1;else 0==m&&(l=m=1),d=D.slice(),g=d.length;if(_>g&&d.unshift(0),r(b,d,_,c),_=b.length,-1==l)for(;n(D,b,A,_)<1;)m++,r(b,_>A?k:D,_,c),_=b.length}else 0===l&&(m++,b=[0]);w[p++]=m,b[0]?b[_++]=T[B]||0:(b=[T[B]],_=1)}while((B++=10;P/=10,p++);S(y,s+(y.e=p+f*I-1)+1,u,h)}else y.e=f,y.r=+h;return y}}(),d=function(){var t=/^(-?)0([xbo])/i,n=/^([^.]+)\.$/,r=/^\.([^.]+)$/,i=/^-?(Infinity|NaN)$/,o=/^\s*\+|^\s+|\s+$/g;return function(a,s,u,c){var l,f=u?s:s.replace(o,"");if(i.test(f))a.s=isNaN(f)?null:0>f?-1:1;else{if(!u&&(f=f.replace(t,function(t,e,n){return l="x"==(n=n.toLowerCase())?16:"b"==n?2:8,c&&c!=l?t:e}),c&&(l=c,f=f.replace(n,"$1").replace(r,"0.$1")),s!=f))return new e(f,l);z&&D(C,"not a"+(c?" base "+c:"")+" number",s),a.s=null}a.c=a.e=null,C=0}}(),R.absoluteValue=R.abs=function(){var t=new e(this);return t.s<0&&(t.s=1),t},R.ceil=function(){return S(new e(this),this.e+1,2)},R.comparedTo=R.cmp=function(t,n){return C=1,a(this,new e(t,n))},R.decimalPlaces=R.dp=function(){var t,e,n=this.c;if(!n)return null;if(t=((e=n.length-1)-i(this.e/I))*I,e=n[e])for(;e%10==0;e/=10,t--);return 0>t&&(t=0),t},R.dividedBy=R.div=function(t,n){return C=3,E(this,new e(t,n),L,j)},R.dividedToIntegerBy=R.divToInt=function(t,n){return C=4,E(this,new e(t,n),0,1)},R.equals=R.eq=function(t,n){return C=5,0===a(this,new e(t,n))},R.floor=function(){return S(new e(this),this.e+1,3)},R.greaterThan=R.gt=function(t,n){return C=6,a(this,new e(t,n))>0},R.greaterThanOrEqualTo=R.gte=function(t,n){return C=7,1===(n=a(this,new e(t,n)))||0===n},R.isFinite=function(){return!!this.c},R.isInteger=R.isInt=function(){return!!this.c&&i(this.e/I)>this.c.length-2},R.isNaN=function(){return!this.s},R.isNegative=R.isNeg=function(){return this.s<0},R.isZero=function(){return!!this.c&&0==this.c[0]},R.lessThan=R.lt=function(t,n){return C=8,a(this,new e(t,n))<0},R.lessThanOrEqualTo=R.lte=function(t,n){return C=9,-1===(n=a(this,new e(t,n)))||0===n},R.minus=R.sub=function(t,n){var r,o,a,s,u=this,c=u.s;if(C=10,t=new e(t,n),n=t.s,!c||!n)return new e(0/0);if(c!=n)return t.s=-n,u.plus(t);var l=u.e/I,f=t.e/I,p=u.c,h=t.c;if(!l||!f){if(!p||!h)return p?(t.s=-n,t):new e(h?u:0/0);if(!p[0]||!h[0])return h[0]?(t.s=-n,t):new e(p[0]?u:3==j?-0:0)}if(l=i(l),f=i(f),p=p.slice(),c=l-f){for((s=0>c)?(c=-c,a=p):(f=l,a=h),a.reverse(),n=c;n--;a.push(0));a.reverse()}else for(o=(s=(c=p.length)<(n=h.length))?c:n,c=n=0;o>n;n++)if(p[n]!=h[n]){s=p[n]0)for(;n--;p[r++]=0);for(n=F-1;o>c;){if(p[--o]0?(u=s,r=l):(a=-a,r=c),r.reverse();a--;r.push(0));r.reverse()}for(a=c.length,n=l.length,0>a-n&&(r=l,l=c,c=r,n=a),a=0;n;)a=(c[--n]=c[n]+l[n]+a)/F|0,c[n]%=F;return a&&(c.unshift(a),++u),T(t,c,u)},R.precision=R.sd=function(t){var e,n,r=this,i=r.c;if(null!=t&&t!==!!t&&1!==t&&0!==t&&(z&&D(13,"argument"+w,t),t!=!!t&&(t=null)),!i)return null;if(n=i.length-1,e=n*I+1,n=i[n]){for(;n%10==0;n/=10,e--);for(n=i[0];n>=10;n/=10,e++);}return t&&r.e+1>e&&(e=r.e+1),e},R.round=function(t,n){var r=new e(this);return(null==t||W(t,0,A,15))&&S(r,~~t+this.e+1,null!=n&&W(n,0,8,15,b)?0|n:j),r},R.shift=function(t){var n=this;return W(t,-B,B,16,"argument")?n.times("1e"+p(t)):new e(n.c&&n.c[0]&&(-B>t||t>B)?n.s*(0>t?0:1/0):n)},R.squareRoot=R.sqrt=function(){var t,n,r,a,s,u=this,c=u.c,l=u.s,f=u.e,p=L+4,h=new e("0.5");if(1!==l||!c||!c[0])return new e(!l||0>l&&(!c||c[0])?0/0:c?u:1/0);if(l=Math.sqrt(+u),0==l||l==1/0?(n=o(c),(n.length+f)%2==0&&(n+="0"),l=Math.sqrt(n),f=i((f+1)/2)-(0>f||f%2),l==1/0?n="1e"+f:(n=l.toExponential(),n=n.slice(0,n.indexOf("e")+1)+f),r=new e(n)):r=new e(l+""),r.c[0])for(f=r.e,l=f+p,3>l&&(l=0);;)if(s=r,r=h.times(s.plus(E(u,s,p,1))),o(s.c).slice(0,l)===(n=o(r.c)).slice(0,l)){if(r.el&&(g=b,b=_,_=g,a=l,l=h,h=a),a=l+h,g=[];a--;g.push(0));for(y=F,v=O,a=h;--a>=0;){for(r=0,m=_[a]%v,d=_[a]/v|0,u=l,s=a+u;s>a;)f=b[--u]%v,p=b[u]/v|0,c=d*f+p*m,f=m*f+c%v*v+g[s]+r,r=(f/y|0)+(c/v|0)+d*p,g[s--]=f%y;g[s]=r}return r?++o:g.shift(),T(t,g,o)},R.toDigits=function(t,n){var r=new e(this);return t=null!=t&&W(t,1,A,18,"precision")?0|t:null,n=null!=n&&W(n,0,8,18,b)?0|n:j,t?S(r,t,n):r},R.toExponential=function(t,e){return h(this,null!=t&&W(t,0,A,19)?~~t+1:null,e,19)},R.toFixed=function(t,e){return h(this,null!=t&&W(t,0,A,20)?~~t+this.e+1:null,e,20)},R.toFormat=function(t,e){var n=h(this,null!=t&&W(t,0,A,21)?~~t+this.e+1:null,e,21);if(this.c){var r,i=n.split("."),o=+X.groupSize,a=+X.secondaryGroupSize,s=X.groupSeparator,u=i[0],c=i[1],l=this.s<0,f=l?u.slice(1):u,p=f.length;if(a&&(r=o,o=a,a=r,p-=r),o>0&&p>0){for(r=p%o||o,u=f.substr(0,r);p>r;r+=o)u+=s+f.substr(r,o);a>0&&(u+=s+f.slice(r)),l&&(u="-"+u)}n=c?u+X.decimalSeparator+((a=+X.fractionGroupSize)?c.replace(new RegExp("\\d{"+a+"}\\B","g"),"$&"+X.fractionGroupSeparator):c):u}return n},R.toFraction=function(t){var n,r,i,a,s,u,c,l,f,p=z,h=this,m=h.c,d=new e(H),g=r=new e(H),y=c=new e(H);if(null!=t&&(z=!1,u=new e(t),z=p,(!(p=u.isInt())||u.lt(H))&&(z&&D(22,"max denominator "+(p?"out of range":"not an integer"),t),t=!p&&u.c&&S(u,u.e+1,1).gte(H)?u:null)),!m)return h.toString();for(f=o(m),a=d.e=f.length-h.e-1,d.c[0]=N[(s=a%I)<0?I+s:s],t=!t||u.cmp(d)>0?a>0?d:g:u,s=M,M=1/0,u=new e(f),c.c[0]=0;l=E(u,d,0,1),i=r.plus(l.times(y)),1!=i.cmp(t);)r=y,y=i,g=c.plus(l.times(i=g)),c=i,d=u.minus(l.times(i=d)),u=i;return i=E(t.minus(r),y,0,1),c=c.plus(i.times(g)),r=r.plus(i.times(y)),c.s=g.s=h.s,a*=2,n=E(g,y,a,j).minus(h).abs().cmp(E(c,r,a,j).minus(h).abs())<1?[g.toString(),y.toString()]:[c.toString(),r.toString()],M=s,n},R.toNumber=function(){var t=this;return+t||(t.s?0*t.s:0/0)},R.toPower=R.pow=function(t){var n,r,i=v(0>t?-t:+t),o=this;if(!W(t,-B,B,23,"exponent")&&(!isFinite(t)||i>B&&(t/=0)||parseFloat(t)!=t&&!(t=0/0)))return new e(Math.pow(+o,t));for(n=V?y(V/I+2):0,r=new e(H);;){if(i%2){if(r=r.times(o),!r.c)break;n&&r.c.length>n&&(r.c.length=n)}if(i=v(i/2),!i)break;o=o.times(o),n&&o.c&&o.c.length>n&&(o.c.length=n)}return 0>t&&(r=H.div(r)),n?S(r,V,j):r},R.toPrecision=function(t,e){return h(this,null!=t&&W(t,1,A,24,"precision")?0|t:null,e,24)},R.toString=function(t){var e,r=this,i=r.s,a=r.e;return null===a?i?(e="Infinity",0>i&&(e="-"+e)):e="NaN":(e=o(r.c),e=null!=t&&W(t,2,64,25,"base")?n(f(e,a),0|t,10,i):q>=a||a>=U?l(e,a):f(e,a),0>i&&r.c[0]&&(e="-"+e)),e},R.truncated=R.trunc=function(){return S(new e(this),this.e+1,1)},R.valueOf=R.toJSON=function(){return this.toString()},null!=t&&e.config(t),e}function i(t){var e=0|t;return t>0||t===e?e:e-1}function o(t){for(var e,n,r=1,i=t.length,o=t[0]+"";i>r;){for(e=t[r++]+"",n=I-e.length;n--;e="0"+e);o+=e}for(i=o.length;48===o.charCodeAt(--i););return o.slice(0,i+1||1)}function a(t,e){var n,r,i=t.c,o=e.c,a=t.s,s=e.s,u=t.e,c=e.e;if(!a||!s)return null;if(n=i&&!i[0],r=o&&!o[0],n||r)return n?r?0:-s:a;if(a!=s)return a;if(n=0>a,r=u==c,!i||!o)return r?0:!i^n?1:-1;if(!r)return u>c^n?1:-1;for(s=(u=i.length)<(c=o.length)?u:c,a=0;s>a;a++)if(i[a]!=o[a])return i[a]>o[a]^n?1:-1;return u==c?0:u>c^n?1:-1}function s(t,e,n){return(t=p(t))>=e&&n>=t}function u(t){return"[object Array]"==Object.prototype.toString.call(t)}function c(t,e,n){for(var r,i,o=[0],a=0,s=t.length;s>a;){for(i=o.length;i--;o[i]*=e);for(o[r=0]+=x.indexOf(t.charAt(a++));rn-1&&(null==o[r+1]&&(o[r+1]=0),o[r+1]+=o[r]/n|0,o[r]%=n)}return o.reverse()}function l(t,e){return(t.length>1?t.charAt(0)+"."+t.slice(1):t)+(0>e?"e":"e+")+e}function f(t,e){var n,r;if(0>e){for(r="0.";++e;r+="0");t=r+t}else if(n=t.length,++e>n){for(r="0",e-=n;--e;r+="0");t+=r}else n>e&&(t=t.slice(0,e)+"."+t.slice(e));return t}function p(t){return t=parseFloat(t),0>t?y(t):v(t)}var h,m,d,g=/^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,y=Math.ceil,v=Math.floor,w=" not a boolean or binary digit",b="rounding mode",_="number type has more than 15 significant digits",x="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_",F=1e14,I=14,B=9007199254740991,N=[1,10,100,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,1e11,1e12,1e13],O=1e7,A=1e9;if(h=r(),"function"==typeof define&&define.amd)define(function(){return h});else if("undefined"!=typeof e&&e.exports){if(e.exports=h,!m)try{m=t("crypto")}catch(k){}}else n.BigNumber=h}(this)},{crypto:31}],web3:[function(t,e,n){var r=t("./lib/web3");r.providers.HttpProvider=t("./lib/web3/httpprovider"),r.providers.QtSyncProvider=t("./lib/web3/qtsync"),r.eth.contract=t("./lib/web3/contract"),r.eth.namereg=t("./lib/web3/namereg"),r.eth.sendIBANTransaction=t("./lib/web3/transfer"),"undefined"!=typeof window&&"undefined"==typeof window.web3&&(window.web3=r),e.exports=r},{"./lib/web3":9,"./lib/web3/contract":11,"./lib/web3/httpprovider":19,"./lib/web3/namereg":23,"./lib/web3/qtsync":26,"./lib/web3/transfer":29}]},{},["web3"]); \ No newline at end of file diff --git a/libjsqrc/ethereumjs/gulpfile.js b/libjsqrc/ethereumjs/gulpfile.js index 360c5242b..558c1181a 100644 --- a/libjsqrc/ethereumjs/gulpfile.js +++ b/libjsqrc/ethereumjs/gulpfile.js @@ -73,7 +73,7 @@ gulp.task('buildLight', ['clean'], function () { .pipe(gulp.dest( DEST )); }); -gulp.task('buildStandalone', ['clean'], function () { +gulp.task('buildStandalone', [], function () { return browserify(browserifyOptions) .require('./' + src + '.js', {expose: 'web3'}) .require('bignumber.js') // expose it to dapp users diff --git a/libjsqrc/ethereumjs/lib/web3.js b/libjsqrc/ethereumjs/lib/web3.js index 982f75d9e..394ae450b 100644 --- a/libjsqrc/ethereumjs/lib/web3.js +++ b/libjsqrc/ethereumjs/lib/web3.js @@ -34,6 +34,7 @@ var Filter = require('./web3/filter'); var utils = require('./utils/utils'); var formatters = require('./web3/formatters'); var RequestManager = require('./web3/requestmanager'); +var Method = require('./web3/method'); var c = require('./utils/config'); var Property = require('./web3/property'); var Batch = require('./web3/batch'); @@ -161,11 +162,11 @@ setupMethods(web3.shh, shh.methods); web3.admin = {}; web3.admin.setSessionKey = function(s) { web3.admin.sessionKey = s; }; -var blockQueueStatus = new Method({ +var blockQueueStatus = new Property({ name: 'blockQueueStatus', call: 'admin_eth_blockQueueStatus', params: 1, - inputFormatter: [function() { return web3.sessionKey; }] + inputFormatter: [function() { return web3.admin.sessionKey; }] }); setupMethods(web3.admin, [blockQueueStatus]); diff --git a/libjsqrc/ethereumjs/lib/web3/property.js b/libjsqrc/ethereumjs/lib/web3/property.js index a2e7282e9..4b2b6c566 100644 --- a/libjsqrc/ethereumjs/lib/web3/property.js +++ b/libjsqrc/ethereumjs/lib/web3/property.js @@ -29,6 +29,7 @@ var Property = function (options) { this.setter = options.setter; this.outputFormatter = options.outputFormatter; this.inputFormatter = options.inputFormatter; + this.params = options.params; }; /** diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index 4a9dd1911..8bdeb6b7a 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -58,7 +58,7 @@ public: void addSession(std::string const& _session, SessionPermissions const& _p) { m_sessions[_session] = _p; } private: - bool isAdmin(std::string const& _session) const { auto it = m_sessions.find(_session); return it != m_sessions.end() && it->second.admin; } + bool isAdmin(std::string const& _session) const override { auto it = m_sessions.find(_session); return it != m_sessions.end() && it->second.admin; } virtual dev::eth::Interface* client() override; virtual std::shared_ptr face() override; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index a0b0e1c89..f88443ee5 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -798,6 +798,83 @@ string WebThreeStubServerBase::eth_compileSerpent(string const& _source) return res; } +bool WebThreeStubServerBase::admin_web3_setVerbosity(int _v, string const& _session) +{ + if (!isAdmin(_session)) + return false; + g_logVerbosity = _v; + return true; +} + +bool WebThreeStubServerBase::admin_net_start(std::string const& _session) +{ + if (!isAdmin(_session)) + return false; + network()->startNetwork(); + return true; +} + +bool WebThreeStubServerBase::admin_net_stop(std::string const& _session) +{ + if (!isAdmin(_session)) + return false; + network()->stopNetwork(); + return true; +} + +bool WebThreeStubServerBase::admin_net_connect(std::string const& _node, std::string const& _session) +{ + if (!isAdmin(_session)) + return false; + p2p::NodeId id; + bi::tcp::endpoint ep; + if (_node.substr(0, 8) == "enode://" && _node.find('@') == 136) + { + id = p2p::NodeId(_node.substr(8, 128)); + ep = p2p::Network::resolveHost(_node.substr(137)); + } + else + ep = p2p::Network::resolveHost(_node); + network()->requirePeer(id, ep); + return true; +} + +Json::Value toJson(p2p::PeerSessionInfo const& _p) +{ + Json::Value ret; + ret["id"] = _p.id.hex(); + ret["clientVersion"] = _p.clientVersion; + ret["host"] = _p.host; + ret["port"] = _p.port; + ret["lastPing"] = (int)chrono::duration_cast(_p.lastPing).count(); + for (auto const& i: _p.notes) + ret["notes"][i.first] = i.second; + for (auto const& i: _p.caps) + ret["caps"][i.first] = (unsigned)i.second; + return ret; +} + +Json::Value WebThreeStubServerBase::admin_net_peers(std::string const& _session) +{ + if (!isAdmin(_session)) + return false; + Json::Value ret; + for (p2p::PeerSessionInfo const& i: network()->peers()) + ret.append(toJson(i)); + return ret; +} + +bool WebThreeStubServerBase::admin_eth_setMining(bool _on, std::string const& _session) +{ + if (!isAdmin(_session)) + return false; + if (_on) + client()->startMining(); + else + client()->stopMining(); + return true; +} + Json::Value WebThreeStubServerBase::eth_compileSolidity(string const& _source) { // TOOD throw here jsonrpc errors diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index 93a54cce7..aaf0a6096 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -137,12 +137,36 @@ public: virtual Json::Value shh_getFilterChanges(std::string const& _filterId); virtual Json::Value shh_getMessages(std::string const& _filterId); - virtual Json::Value admin_eth_blockQueueStatus(std::string const&) { return Json::Value(); } + virtual bool admin_web3_setVerbosity(int _v, std::string const& _session); + virtual bool admin_net_start(std::string const& _session); + virtual bool admin_net_stop(std::string const& _session); + virtual bool admin_net_connect(std::string const& _node, std::string const& _session); + virtual Json::Value admin_net_peers(std::string const& _session); + + virtual bool admin_eth_setMining(bool _on, std::string const& _session); + virtual Json::Value admin_eth_blockQueueStatus(std::string const& _session) { (void)_session; return Json::Value(); } + virtual bool admin_eth_setAskPrice(std::string const& _wei, std::string const& _session) { (void)_wei; (void)_session; return false; } + virtual bool admin_eth_setBidPrice(std::string const& _wei, std::string const& _session) { (void)_wei; (void)_session; return false; } + virtual bool admin_eth_setReferencePrice(std::string const& _wei, std::string const& _session) { (void)_wei; (void)_session; return false; } + virtual bool admin_eth_setPriority(int _percent, std::string const& _session) { (void)_percent; (void)_session; return false; } + virtual Json::Value admin_eth_findBlock(std::string const& _blockHash, std::string const& _session) { (void)_blockHash; (void)_session; return Json::Value(); } + virtual std::string admin_eth_blockQueueFirstUnknown(std::string const& _session) { (void)_session; return ""; } + virtual bool admin_eth_blockQueueRetryUnknown(std::string const& _session) { (void)_session; return false; } + virtual Json::Value admin_eth_allAccounts(std::string const& _session) { (void)_session; return Json::Value(); } + virtual Json::Value admin_eth_newAccount(const Json::Value& _info, std::string const& _session) { (void)_info; (void)_session; return Json::Value(); } + virtual bool admin_eth_setSigningKey(std::string const& _uuidOrAddress, std::string const& _session) { (void)_uuidOrAddress; (void)_session; return false; } + virtual bool admin_eth_setMiningBenefactor(std::string const& _uuidOrAddress, std::string const& _session) { (void)_uuidOrAddress; (void)_session; return false; } + virtual Json::Value admin_eth_inspect(std::string const& _address, std::string const& _session) { (void)_address; (void)_session; return Json::Value(); } + virtual Json::Value admin_eth_reprocess(std::string const& _blockNumberOrHash, std::string const& _session) { (void)_blockNumberOrHash; (void)_session; return Json::Value(); } + virtual Json::Value admin_eth_vmTrace(std::string const& _blockNumberOrHash, std::string const& _txIndex, std::string const& _session) { (void)_blockNumberOrHash; (void)_txIndex; (void)_session; return Json::Value(); } + virtual Json::Value admin_eth_getReceiptByHashAndIndex(std::string const& _blockNumberOrHash, std::string const& _txIndex, std::string const& _session) { (void)_blockNumberOrHash; (void)_txIndex; (void)_session; return Json::Value(); } void setIdentities(std::vector const& _ids); std::map const& ids() const { return m_shhIds; } protected: + virtual bool isAdmin(std::string const& _session) const { (void)_session; return false; } + virtual dev::eth::Interface* client() = 0; virtual std::shared_ptr face() = 0; virtual dev::WebThreeNetworkFace* network() = 0; diff --git a/libweb3jsonrpc/abstractwebthreestubserver.h b/libweb3jsonrpc/abstractwebthreestubserver.h index 675a03614..6b94c31da 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -76,7 +76,28 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(jsonrpc::Procedure("shh_uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_uninstallFilterI); this->bindAndAddMethod(jsonrpc::Procedure("shh_getFilterChanges", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_getFilterChangesI); this->bindAndAddMethod(jsonrpc::Procedure("shh_getMessages", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::shh_getMessagesI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_web3_setVerbosity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_web3_setVerbosityI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_net_start", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_net_startI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_net_stop", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_net_stopI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_net_connect", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_net_connectI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_net_peers", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_net_peersI); this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_blockQueueStatus", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_blockQueueStatusI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_setAskPrice", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_setAskPriceI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_setBidPrice", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_setBidPriceI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_setReferencePrice", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_setReferencePriceI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_setPriority", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_INTEGER,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_setPriorityI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_setMining", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_BOOLEAN,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_setMiningI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_findBlock", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_findBlockI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_blockQueueFirstUnknown", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_blockQueueFirstUnknownI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_blockQueueRetryUnknown", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_blockQueueRetryUnknownI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_allAccounts", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_allAccountsI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_newAccount", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_OBJECT,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_newAccountI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_setSigningKey", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_setSigningKeyI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_setMiningBenefactor", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_setMiningBenefactorI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_inspect", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_inspectI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_reprocess", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_reprocessI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_vmTrace", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_vmTraceI); + this->bindAndAddMethod(jsonrpc::Procedure("admin_eth_getReceiptByHashAndIndex", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::admin_eth_getReceiptByHashAndIndexI); } inline virtual void web3_sha3I(const Json::Value &request, Json::Value &response) @@ -352,10 +373,94 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServershh_getMessages(request[0u].asString()); } + inline virtual void admin_web3_setVerbosityI(const Json::Value &request, Json::Value &response) + { + response = this->admin_web3_setVerbosity(request[0u].asInt(), request[1u].asString()); + } + inline virtual void admin_net_startI(const Json::Value &request, Json::Value &response) + { + response = this->admin_net_start(request[0u].asString()); + } + inline virtual void admin_net_stopI(const Json::Value &request, Json::Value &response) + { + response = this->admin_net_stop(request[0u].asString()); + } + inline virtual void admin_net_connectI(const Json::Value &request, Json::Value &response) + { + response = this->admin_net_connect(request[0u].asString(), request[1u].asString()); + } + inline virtual void admin_net_peersI(const Json::Value &request, Json::Value &response) + { + response = this->admin_net_peers(request[0u].asString()); + } inline virtual void admin_eth_blockQueueStatusI(const Json::Value &request, Json::Value &response) { response = this->admin_eth_blockQueueStatus(request[0u].asString()); } + inline virtual void admin_eth_setAskPriceI(const Json::Value &request, Json::Value &response) + { + response = this->admin_eth_setAskPrice(request[0u].asString(), request[1u].asString()); + } + inline virtual void admin_eth_setBidPriceI(const Json::Value &request, Json::Value &response) + { + response = this->admin_eth_setBidPrice(request[0u].asString(), request[1u].asString()); + } + inline virtual void admin_eth_setReferencePriceI(const Json::Value &request, Json::Value &response) + { + response = this->admin_eth_setReferencePrice(request[0u].asString(), request[1u].asString()); + } + inline virtual void admin_eth_setPriorityI(const Json::Value &request, Json::Value &response) + { + response = this->admin_eth_setPriority(request[0u].asInt(), request[1u].asString()); + } + inline virtual void admin_eth_setMiningI(const Json::Value &request, Json::Value &response) + { + response = this->admin_eth_setMining(request[0u].asBool(), request[1u].asString()); + } + inline virtual void admin_eth_findBlockI(const Json::Value &request, Json::Value &response) + { + response = this->admin_eth_findBlock(request[0u].asString(), request[1u].asString()); + } + inline virtual void admin_eth_blockQueueFirstUnknownI(const Json::Value &request, Json::Value &response) + { + response = this->admin_eth_blockQueueFirstUnknown(request[0u].asString()); + } + inline virtual void admin_eth_blockQueueRetryUnknownI(const Json::Value &request, Json::Value &response) + { + response = this->admin_eth_blockQueueRetryUnknown(request[0u].asString()); + } + inline virtual void admin_eth_allAccountsI(const Json::Value &request, Json::Value &response) + { + response = this->admin_eth_allAccounts(request[0u].asString()); + } + inline virtual void admin_eth_newAccountI(const Json::Value &request, Json::Value &response) + { + response = this->admin_eth_newAccount(request[0u], request[1u].asString()); + } + inline virtual void admin_eth_setSigningKeyI(const Json::Value &request, Json::Value &response) + { + response = this->admin_eth_setSigningKey(request[0u].asString(), request[1u].asString()); + } + inline virtual void admin_eth_setMiningBenefactorI(const Json::Value &request, Json::Value &response) + { + response = this->admin_eth_setMiningBenefactor(request[0u].asString(), request[1u].asString()); + } + inline virtual void admin_eth_inspectI(const Json::Value &request, Json::Value &response) + { + response = this->admin_eth_inspect(request[0u].asString(), request[1u].asString()); + } + inline virtual void admin_eth_reprocessI(const Json::Value &request, Json::Value &response) + { + response = this->admin_eth_reprocess(request[0u].asString(), request[1u].asString()); + } + inline virtual void admin_eth_vmTraceI(const Json::Value &request, Json::Value &response) + { + response = this->admin_eth_vmTrace(request[0u].asString(), request[1u].asString(), request[2u].asString()); + } + inline virtual void admin_eth_getReceiptByHashAndIndexI(const Json::Value &request, Json::Value &response) + { + response = this->admin_eth_getReceiptByHashAndIndex(request[0u].asString(), request[1u].asString(), request[2u].asString()); + } virtual std::string web3_sha3(const std::string& param1) = 0; virtual std::string web3_clientVersion() = 0; virtual std::string net_version() = 0; @@ -420,7 +525,28 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerCallMethod("admin_web3_setVerbosity",p); + if (result.isBool()) + return result.asBool(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + bool admin_net_start(const std::string& param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("admin_net_start",p); + if (result.isBool()) + return result.asBool(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + bool admin_net_stop(const std::string& param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("admin_net_stop",p); + if (result.isBool()) + return result.asBool(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + bool admin_net_connect(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + p.append(param2); + Json::Value result = this->CallMethod("admin_net_connect",p); + if (result.isBool()) + return result.asBool(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + Json::Value admin_net_peers(const std::string& param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("admin_net_peers",p); + if (result.isArray()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } Json::Value admin_eth_blockQueueStatus(const std::string& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; @@ -681,6 +733,181 @@ class WebThreeStubClient : public jsonrpc::Client else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } + bool admin_eth_setAskPrice(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + p.append(param2); + Json::Value result = this->CallMethod("admin_eth_setAskPrice",p); + if (result.isBool()) + return result.asBool(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + bool admin_eth_setBidPrice(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + p.append(param2); + Json::Value result = this->CallMethod("admin_eth_setBidPrice",p); + if (result.isBool()) + return result.asBool(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + bool admin_eth_setReferencePrice(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + p.append(param2); + Json::Value result = this->CallMethod("admin_eth_setReferencePrice",p); + if (result.isBool()) + return result.asBool(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + bool admin_eth_setPriority(int param1, const std::string& param2) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + p.append(param2); + Json::Value result = this->CallMethod("admin_eth_setPriority",p); + if (result.isBool()) + return result.asBool(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + bool admin_eth_setMining(bool param1, const std::string& param2) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + p.append(param2); + Json::Value result = this->CallMethod("admin_eth_setMining",p); + if (result.isBool()) + return result.asBool(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + Json::Value admin_eth_findBlock(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + p.append(param2); + Json::Value result = this->CallMethod("admin_eth_findBlock",p); + if (result.isObject()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + std::string admin_eth_blockQueueFirstUnknown(const std::string& param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("admin_eth_blockQueueFirstUnknown",p); + if (result.isString()) + return result.asString(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + bool admin_eth_blockQueueRetryUnknown(const std::string& param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("admin_eth_blockQueueRetryUnknown",p); + if (result.isBool()) + return result.asBool(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + Json::Value admin_eth_allAccounts(const std::string& param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("admin_eth_allAccounts",p); + if (result.isArray()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + Json::Value admin_eth_newAccount(const Json::Value& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + p.append(param2); + Json::Value result = this->CallMethod("admin_eth_newAccount",p); + if (result.isObject()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + bool admin_eth_setSigningKey(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + p.append(param2); + Json::Value result = this->CallMethod("admin_eth_setSigningKey",p); + if (result.isBool()) + return result.asBool(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + bool admin_eth_setMiningBenefactor(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + p.append(param2); + Json::Value result = this->CallMethod("admin_eth_setMiningBenefactor",p); + if (result.isBool()) + return result.asBool(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + Json::Value admin_eth_inspect(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + p.append(param2); + Json::Value result = this->CallMethod("admin_eth_inspect",p); + if (result.isObject()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + Json::Value admin_eth_reprocess(const std::string& param1, const std::string& param2) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + p.append(param2); + Json::Value result = this->CallMethod("admin_eth_reprocess",p); + if (result.isObject()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + Json::Value admin_eth_vmTrace(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + p.append(param2); + p.append(param3); + Json::Value result = this->CallMethod("admin_eth_vmTrace",p); + if (result.isObject()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } + Json::Value admin_eth_getReceiptByHashAndIndex(const std::string& param1, const std::string& param2, const std::string& param3) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + p.append(param2); + p.append(param3); + Json::Value result = this->CallMethod("admin_eth_getReceiptByHashAndIndex",p); + if (result.isObject()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } }; #endif //JSONRPC_CPP_STUB_WEBTHREESTUBCLIENT_H_ From 7d55e9123ef44d8c7108e04f541ba41703159dfd Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 13 Jun 2015 18:11:16 +0800 Subject: [PATCH 36/40] Show import timing. --- libethereum/Client.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 657e25772..f24c88e0e 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -622,6 +622,9 @@ void Client::syncBlockQueue() boost::timer t; tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, m_syncAmount); double elapsed = t.elapsed(); + + cnote << m_syncAmount << "blocks imported in" << unsigned(elapsed * 1000) << "ms (" << (m_syncAmount / elapsed) << "blocks/s)"; + if (elapsed > 0.55 && m_syncAmount > c_syncMin) m_syncAmount = max(c_syncMin, m_syncAmount * 9 / 10); else if (elapsed < 0.45 && m_syncAmount < c_syncMax) From 425c9aaeeb60a315cbb0c13e77151d4f9a8ce799 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 14 Jun 2015 11:49:26 +0800 Subject: [PATCH 37/40] Use relative bounds to target. --- libethereum/Client.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index f24c88e0e..31c2e8026 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -613,7 +613,7 @@ bool Client::submitWork(ProofOfWork::Solution const& _solution) unsigned static const c_syncMin = 1; unsigned static const c_syncMax = 100; -double static const c_targetDuration = 0.5; +double static const c_targetDuration = 1; void Client::syncBlockQueue() { @@ -625,9 +625,9 @@ void Client::syncBlockQueue() cnote << m_syncAmount << "blocks imported in" << unsigned(elapsed * 1000) << "ms (" << (m_syncAmount / elapsed) << "blocks/s)"; - if (elapsed > 0.55 && m_syncAmount > c_syncMin) + if (elapsed > c_targetDuration * 1.1 && m_syncAmount > c_syncMin) m_syncAmount = max(c_syncMin, m_syncAmount * 9 / 10); - else if (elapsed < 0.45 && m_syncAmount < c_syncMax) + else if (elapsed < c_targetDuration * 0.9 && m_syncAmount < c_syncMax) m_syncAmount = min(c_syncMax, m_syncAmount * 11 / 10 + 1); if (ir.first.empty()) return; From 0426393557eaa793fe5dfc5c6b9a7d60c5f58a5b Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 14 Jun 2015 12:37:29 +0800 Subject: [PATCH 38/40] Include hash in client ID. --- eth/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/main.cpp b/eth/main.cpp index 259a993c9..4b23ef62a 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -685,7 +685,7 @@ int main(int argc, char** argv) VMFactory::setKind(jit ? VMKind::JIT : VMKind::Interpreter); auto netPrefs = publicIP.empty() ? NetworkPreferences(listenIP ,listenPort, upnp) : NetworkPreferences(publicIP, listenIP ,listenPort, upnp); auto nodesState = contents((dbPath.size() ? dbPath : getDataDir()) + "/network.rlp"); - std::string clientImplString = "++eth/" + clientName + "v" + dev::Version + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : ""); + std::string clientImplString = "++eth/" + clientName + "v" + dev::Version + "-" + string(DEV_QUOTED(ETH_COMMIT_HASH)).substr(0, 8) + (ETH_CLEAN_REPO ? "" : "*") + "/" DEV_QUOTED(ETH_BUILD_TYPE) "/" DEV_QUOTED(ETH_BUILD_PLATFORM) + (jit ? "/JIT" : ""); dev::WebThreeDirect web3( clientImplString, dbPath, From fe011b3563af02f52ef83a1522935fb48eda2b69 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sun, 14 Jun 2015 12:38:49 +0800 Subject: [PATCH 39/40] Avoid building neth unless made explicit, at least until build works again. --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a2ac51a5..fd3188eae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ option(ETHKEY "Build the CLI key manager component" ON) option(SOLIDITY "Build the Solidity language components" ON) option(SERPENT "Build the Serpent language components" ON) option(TOOLS "Build the tools components" ON) -option(NCURSES "Build the NCurses components" ON) +option(NCURSES "Build the NCurses components" OFF) option(GUI "Build GUI components (AlethZero, Mix)" ON) option(TESTS "Build the tests." ON) option(EVMJIT "Build just-in-time compiler for EVM code (requires LLVM)" OFF) @@ -222,7 +222,7 @@ elseif (BUNDLE STREQUAL "full") set(SOLIDITY ON) set(USENPM ON) set(GUI ON) - set(NCURSES ${DECENT_PLATFORM}) +# set(NCURSES ${DECENT_PLATFORM}) set(TOOLS ON) set(TESTS ON) set(FATDB ON) @@ -249,7 +249,7 @@ elseif (BUNDLE STREQUAL "user") set(SOLIDITY OFF) set(USENPM OFF) set(GUI ON) - set(NCURSES ${DECENT_PLATFORM}) +# set(NCURSES ${DECENT_PLATFORM}) set(TOOLS ON) set(TESTS OFF) elseif (BUNDLE STREQUAL "wallet") From 9570c72e379a8620fddc59317d6b2137ce73f42d Mon Sep 17 00:00:00 2001 From: Marek Kotewicz Date: Sun, 14 Jun 2015 07:36:34 +0200 Subject: [PATCH 40/40] new osx dragndrop installer --- CMakeLists.txt | 2 +- appdmg.json.in | 8 ++++---- bg.png | Bin 175517 -> 0 bytes install-folder-bg.png | Bin 0 -> 14542 bytes install-folder-bg@2x.png | Bin 0 -> 35073 bytes 5 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 bg.png create mode 100644 install-folder-bg.png create mode 100644 install-folder-bg@2x.png diff --git a/CMakeLists.txt b/CMakeLists.txt index fd3188eae..71d12353c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -458,7 +458,7 @@ if (APPLE AND GUI) -DAPP_DMG_EXE=${ETH_APP_DMG} -DAPP_DMG_FILE=appdmg.json.in -DAPP_DMG_ICON="alethzero/alethzero.icns" - -DAPP_DMG_BACKGROUND="bg.png" + -DAPP_DMG_BACKGROUND="install-folder-bg.png" -DETH_BUILD_DIR="${CMAKE_BINARY_DIR}" -DETH_MIX_APP="$" -DETH_ALETHZERO_APP="$" diff --git a/appdmg.json.in b/appdmg.json.in index 4fb9a6e33..ea49e9294 100644 --- a/appdmg.json.in +++ b/appdmg.json.in @@ -2,11 +2,11 @@ "title": "Ethereum", "icon": "appdmg_icon.icns", "background": "appdmg_background.png", - "icon-size": 80, + "icon-size": 55, "contents": [ - { "x": 600, "y": 170, "type": "link", "path": "/Applications" }, - { "x": 150, "y": 90, "type": "file", "path": "${ETH_ALETHZERO_APP}" }, - { "x": 150, "y": 260, "type": "file", "path": "${ETH_MIX_APP}" } + { "x": 242, "y": 240, "type": "link", "path": "/Applications" }, + { "x": 145, "y": 125, "type": "file", "path": "${ETH_ALETHZERO_APP}" }, + { "x": 339, "y": 125, "type": "file", "path": "${ETH_MIX_APP}" } ] } diff --git a/bg.png b/bg.png deleted file mode 100644 index 869290c2b861dd148e1ae500770f3bc47879761e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 175517 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
-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�I*sMH@QHEDf(ql`);jlqV0D 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 literal 0 HcmV?d00001 diff --git a/install-folder-bg@2x.png b/install-folder-bg@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..31aac5522ee552c079977c054adaa41f8b09886f GIT binary patch literal 35073 zcmeFZXH-*L*FOqKQ4moPIMR;@C_86-~@ZdSK+XtuG7khuT9&gVlcp(f=3Y>V*g9fcWo;XqlQiI1CkaZIA048e)b^Ep^+y$wYjW z6Q=6p;Hk2;-p@)-tx)P9Q}b}~2=L@v_3u;2cnS#@DON;DzW(&yvRAM0ZuOVVKFtt%<_&JjP@A0d za7hz!1ZDq{w8*v%@$y52&D>?&x za~pK5wSjr!9um>ayqqs@h4Eh1^q0*jcE}TPYz=BO80xj-s>Vmm$otMyiK=ESm%cxr z>WFFRAr1}ttj1m77;*c-Ab9P=UdQ&7j<&%wfzZkVF)mot=3Y;dHUBX zX|&E4Q#Ot1YX$aZ`mVxB$q+wke;O z`Fmw)it9JtK|FswxQN@%iZ_R{fcIP<@9b~HBP%e@2(c`$7uWW}UHpIS@1z|_XX(2j zDKK(;;7~49VDfUg zda%7v49(P#MIctxqijckH0A;80u42@gYgypj=#UZ8qCp58}_@Kx;HHhzLC-qu-g~k zXmtRPxqwt#Tu<9yNK->~Y0A*cto;1>bKmr$Pd#}BfuBusapvF#?@Y&Blpb8C^Peds zEx!^Jox(ldt$h*yJ7jm{55q>oiF$=pr*Gn~>tgig3v1|} zWySjM3~8Dtb*V>5(VW~$2fz-?v+}F7zB-Dah=d}D?vAO+Xh2O?nZ$^Q>a&Y42Firu z#2)g#o#}Ou-r2v~d46-=j_d9?lTO_I46Ew=L8jIE%?J`H--6Q4bQwv;u4bEgq|`J# z$29l6XzYHe8YL$q;_}5i%0p)^HE`dai;4Z(nllvQ=QJD8EOq<#FbR1;v20|0@v&MU zRIOoX@|vVG4o{IMk1{Tq8avOW%Ajo!-%7rgT-Qx{B%9V3{Y-XY`&X6KjEsbYyp7DA z@oDb8Z$?}RAnStaLbKf-jDzIJ>VAE1qUoqf=vU?4IMJTcUrG$KIybH|(VTp#7c_Av zlOYa!kKdFAI+zG;_r%-UVpenUo>i1>(v$?lQ{m6@zV-oRiPMW zP#K=b#*$d}`-{!;Lbl^aQM&{gkuYdlan0nr_h{aw=Z(Zshr3~aJ#V0fi#qLQPRT%! zztEC{2%E}XjQ2#8(@5>m1%9&qL6c0ewo>rr@e()SyNg`iW^wBH2)SeRzXMG zkCbFnpP(Q18iK?d#6WnEZ87~W**<-bgh#C7A%inFMjHI8#Vi`fm{KPl^w27#*Idrm zL63NE*{F?%s;XBPBlmqpMMasC@ywDhdt&d{f5IVedCD-&fdV<3 z2G!9@X_qeBpoo=D7)_nYEOXAYw)CMr+v*hTdT_qg$?tKfVkDzodU_gV*;c+zJQYwkPOse&b4SCv)a|?#`Ixu#A(zN(j+_rh~7b~}Auf~@T>hrk~EDV^h1NLxs{!#F>a^`&7`BE`} z-*-V!W<902rK_d(o|8*v5`k6iIa4`Evxoav#;~zjy@WZrxnz&!QWWndG;Au~upi1C z6zkk44KW-t=!kPR*EYfx%WK$L5L`B7aXT6^##^Ixj2~^&p4Y>Pufv>5@`H)}CwdwN zizJE;0$k)$&kwN}sec3A(HGM3k6Cmpy1En8n82eg_wb@A7KtOLLB_g{*eA8e-IT7V8Jon{bZCX{jR5gT5@=~vjBq|XZ<{#&{E{0MD6T?fdO`cdA zPLkid--SI`n~Ptz9vZ-E>b69zLEm?bO&nFU=~6(o>Zg?AbP0I;IaaN-1x@&(E}kfZ zJ5d0Wjrk!l5UR5oLw?k+PTA=RBwA!|ea+qgZ#S_#Te3?IQqyE%>yYcv9Ed0EGHFCQ zS@#p=iQ_F!r9%xnmm9%rNvlq`>8ckl)3xkh(B@Qxj=uc0U=>fS8|70+S2z-08=2n{ z=CkF4^@DDF(|`X`_#}TX6HwAN1a%7mRdw(c#?BPkYHYe=B7;op{G4`$s%;wEw}6e9 zw2Hny9SJVb14G=@c5q*Gm&IKIlSKVl)4ef|p31Ab+0Ev2m>AZU$ch_3A~eobxQ^r{ z55I~Lj*#r?DacgR>F3IdiE9bhflqF0XWM7^ilWg{qY}K&2ge~ukikpoe&JCIv**5! zX_kCzw1-ypl={UKFTJe?pe02;y4!Yf&>NJ@Z1i24+ktT27}ltD!FaPt%8tX8Z|apq zBlS`?J+dXoywUy-@Sc*1z$^01LKo^*w)z{VfS;pX2Bz`*73QUO>7*GHHU_ijw^vn+U9ROk*$R6896!C+TN(T$eQO#zMPYYR(l?xHuCh z?e@NY&b9gQVFnbx*0Ta1t-_Da&E)L7EKc-(2f0peem|`#bSN4jz?g1*e#m=76_!zs zvejS8w_swlDTo@n?43l-M9XexXICQaG5fr!Anh#;*2*Cgq_gV{WZ2<#U0o+SjG&-k zDQVAt6R#ayntf)Y|Fx5f1BgQMopS5@^xI$o8WnqCOr(`LdNN7RfnQvm1Kn@m(cM7Q z<@jrLJg^tzdG{_Kxg)HnmV(ab^7h`#C$M(s7`P!LIn8%7qwr z+titBtWokbC#OFE$b^^Y+Pim(bu@YSzpX9!O}j_hr7)KeFnpP*bL~$_CmETqy`2fS zFz9F5y087c9@(aa6#0$&%vE}5W)qEqE3*UNrP-Ro!$Faie4Y$qnneXtR*LEcSNvEi z(9SL6^FM`i)Ofitbx;e6P+O@K!l%r0rf&FrA}{n!l2D#-e>NH|+ zqk|Iv`S~>o(YJUNxRNRV9P)D#O=T$OUi?LP!4-+O1n-qAQy-M*hqX9rTrk){O~Vr& zkejx?Dq*~vsS)_-8tuHPoKP8?-`DCt+e`%dFIs!+&bVG9*+`{%hHYLxB)(Qe(KR_= z<+c0YQBQ-VaQ^+bV>O~O`HY7k-YM|)FpJY=zUGA1v54P>`**xqA2?qhTk!i^F^Sa^IhPl_Ap&4~A zCyWHH1(G8&tQSPm^uXkKHV>!v;fxF&?~2CVQ{bvK=GBZW@rnBF&X|}*se;)~KNjwd z!Tt)Ze&L9PE98QDQs0I?vDc&6bW-YmzHHixuj6MpQ9`0B0L^ARBAIZg?S+$`@XCk6 zwu29-f|JkRah(XtrN3g=H}OdOA(y1%b;^v1%=5J;CMZn-C0h}o{_NU{hxSdVGrmXe z%}C_bL327BQl|mrpgUjPFw%m_?#9XQY$TPcpXM^M6y^bsrut^#8$t-oL=1|3 zxR9@&-}b%bs~I48-Z!6^NAqu7paSBRA3UXw>KnzqZP2uY-ra;tP2Cwqd&kQHtl4a*Tp+wbvS$n>_O~vsf82C?F_cD&UdW zgXL%BFec4Nu@2V5sKx;VUXR~bwCHJl6%{LCAq*^M>a)}a<>SyEXD_-%gCr4siP~4Hgo}&WOax{Zl+CwaNwr+rsI+>lW62cXXE>?EGMbl@vJzm4|X% zTc7>JD|=}>+!P#m#JJi?pm%ZagWTEH6V&L@2U$d^lpmkZeIyf>;x*XKd;hxq2JiSI z?{8*KDp;ItFUcz-Q#8ZHe~QaIJd?(ft^=w8N9!Aoyg3J9k-Ly7=RW9zMFt-5=d1Yg zjQkwpb=ZOe=)R;#P&ID&2MZt1OX%W2?s&TYQ@YI%5Z=Pre%AC(=2EuFq`mlr-ln@C zsBq=logxRj3U9Nn(li@&o+U8;1FBzBX1vI~vYC!YjmJn=|EUz@CdwIkVB9}p#@V*p zjWXY&pYO9h+;~Z^ri&QwTf#?|zyVmF7qqg7!j1GSwrt$lRQu~Hf2VT0L1S)QrEG?M zfA$D&uM5{)rhm&peePr7M^W*FQDpNV57sBA9D*bc_bBPg<-YoUu-9{7r1az0LfCB` zxV3c_(rBJnYIT?klhY(G$KmSu11qQ94+R&xQz9K$&}0dWeBMYU7}8e~Ofl0d!1xaZ#R(4_Z# zS#`n=;i%f|UmR&}?xEI?{XM$395}%{<^bJf+ zxkP{1g2~4Dd3o;|&R|$Ux#Oj_fsWP6EL~$2wxw#f*6xcj+O(i~Q6y1fIj;O5y%1CX z!!OsSD+Sa*jPIGY)PARHk^9;wlgnpJ6MA!hBPpK}FL#)d8ZIfij)^WiUI3umN#wUK zDV(Eis*jDM3TUlAZGS6gc*#HTrtg+rSTS0^t2A5bv2dYj^~xuoBw_W$j~a27c=4(rHa_7GRz>;5PrcDxTxfG9xq$lh?SwO6! z6oyWs+tk?DOh1RFZJ+SekK^H4UjIB7KTI}-5nUe*a|7VW73jNcf2Hd=+CRH_B|R9? zxYOlgviGLO&g6}x<^U?Yy}Dh5h`+4ZsV-_huatOQg{ zOygrxC+OrPhqTyB1gHJy=X_%N>YY47fS$Ir*Vl$i?9$Gx$xX?{=c@x`?ZIpzrJ;RY|xJ!S_aW^EA0*dNH6meyQMMjN0Z6 zvOQ%Gk}WiN6pnJ}fU4Of8UJ^07|mPV=B;Pi!=6;Z{_+8=!WtD4{=b<@<;Q`p(bb?% zy+w5n0>eHANx{GneFFp2;oEz~2fM|viEqKMG{MH+)&bm3xA*d>Lvbb0iLWGYEAj0{ zNzJ(;q`55?#=-Nw)ZMk_Zn_Y&GoS4Z+!B3}YXek)T^ThsYHfbbPpPknVsQ9i996{WS= zF*!Loj`{G$*;rlJYj5wW_luibgX_Ak{s3T3P`+odd)SEPJJ?3ylRdgm)rpS#HmdrE zJ4Br(tX{GcTX3qz&UP`^+x_}7oSl@Egy+I-zs3e0P>8vj@OJUK`AaTPQ70v92r{4{ zw`w~cxtEo@W5P$;~btfY6muqFh3(KJBX@zP?H~pxMH`1Zxs&ErR+rC zhF0>OMlKL%Ub+cbZt~_6{W?p=k|Xj&ag$#zk=L?pM_3NFU-IO+Y_X%aG?cJrT{|^k z2wpS|;BtlWEce_>>1V5xR(ccRQsX5+X2?pJtM}PlCSqJPW%+JCRG+|l<0@k`HJs1< zDsoo<`sK^rva8F`4+Z|&!C3?KyV*(38yklBycg{`X#p~>T6ynbD`WORrCs@5pi3=; zJz#mblsFN>V&dcD({60{I0tvIPl6H9hDrM=KXYa};xRZ17Uz>;lD}G#eZMcrDv_95 zR5W!rRF4b3+CUmz`~738eA0(1xbC&`A*v%|oLq{rR?s4@wA(IgD#dqDuTR^7#SHgu z)^7Vx&VL?%IIx(8=^bz+$@_VpS>N6X@hDw}#O5Mpc{$UUI9TN72w6Y_Xm{DdJh@-M z#k*3||1}lOjv!DIS)juDE}b<}tc=Jv%mIf^Z?8|Ch!189VY)3TX*0de%q4m4`QLqJ zx+gp+lN`vBoy|EvX)&XcZ%hMVVre8@xACS>F$5vGw!8nX9mO}?8YmHqnu?I^zMURN zU*bFcK_$Xizbl7gvT3RC-fwC$OoB*1!ztx#HinQ3=gWO-a?GttJ)w`=kg0G2sTC>Tx0EF-PH8w@#M<8NQg&Dk9xET{(3U- zRona)6icNQGjH|cDVPP6VbJfv+|E|vQ=Jyi%NnUYdE>o>BzA7UbZhgJd&JI?(B|;O zi*aTQOt^ghMu(j_++HG z?t5TDb);?2Cr2)b(*f6N6(M7A48YwZOPM;*`5in}C}!4>(*g8OnLn>Y;3gClu5Jl=Ni4RO}+r*0Q z9=Rt=dt{>r2W<+#MP_=NNzQ@Ju@%*jsywEsW|C1iymY)nPlt)+0QaHFSXVbDw*WJf0heCLjH%x=?WrtOTTwxTXRUon zPmk1(jW_nnBIjQzKiZDc{^8iU7VHCh=V6GD>m>X{QyDC(;B$1dBM51;lqs*do+>Yk(V9_*aH=-u!0sQ{6h2B-?fds0F)EZMkvW96I?H2$xS;d%<`$^othEJcDZ; zMRsaa)xRjnXoeVQ=U|#}(&T*g6ta7ec-~>9f^Rg(N>`i*>G)S})h}?%=#Z6zDqs*J zmbv20m}-}5IGN~^Z--Gu?OJmAWhn&hp*gSrXhFj=?<6mb(UYf)5*L zT0pBR-Mt|6=<0ty&T>*KOP=idY^CyFM|EBRL5?BT^03PVB=>(lf_nk%A3Cd5CUD#x zJnSqVeY*=}t&sLo-s7u({;6mO7>km}m63D*v%=9@!RbIN_U?=k%l}#V@EiYaVED82 z$K{j%waot`?JuT!xgWz0`>6jxCI45T6Q(6ScnDGcWBg<|Fl={5Q1-?DaDPPo*~2}q zuiQ(AO`d-U2fn>j28M5kM)TbLuVsKf5Vu|g;XhVBeD=M=?V?1bwut``$?;mWZ2Wi5 zh@gD`W97pcpU(lq|BC%zvHxrB{|1?VgUtV3Uivq-|C>_(O{xE1LNZqv>n-2m%}tQQ~1Ad6m`XmqHT z=qVR=-Cld@V2`%QudG8EkW2zYO~r^~eubnnNo3g#J5(c4HFsujI<747-OVLK{aNHs zfkRZL_yz!&O8%}RphKK!t_a>rN`wsbo@ir=hFmUGtSu>tWb=unGtiqiM^KqWI`y2& z^qX*t9Fbx(|>crTpI zA51;$ECFga0@VJ)*J?!K5XlFB3WCZJsvQDThPLYJz6|8GKd$#luw+_qW?h56fq2+s zjkL7X6g%GrAKrYH4XAj&a@!MG583#}x<(dVb>)c@g#?*Fv?oCgD;Yjnmy$WL{3Z;G zob~BOT?5DFaPs~ky-<~8%7a7XzeYQtSW`8Qj;KS@45=7{+Tf7zGJ4{>$9?`koVt3r z{?ZZ^VMw9eKb$+S$1j7Vk`bIZaYXJ{CcAMgC6u!sOouv=*WS=n|9$aG;&1s%ud0J5 zA-}@z6sROn4x9OBAL;{-)V~pT*vvnBvNC9P5nE3Vl8Sc^t){*Wf zVO%{(i|;<{3@{H62o<1Q>Ruzd!z=zh8s;LFl|lJR106j(N`6PZ&Cm|#<$Q1{^d03F z;z!`tu+rg8)U-MrK;IVo9&~hZ>2mKp)U+BeZHHi5GK(@>$qo@|OG=!km%2w#Zu@cX^U(v{^%d`K%t9FIIj8S}*bI!cqI4gizde&B@!e#;seB|3 zfU{{p@iEoU9vxHsjAjw(SMs@yo>b`SAsF8>zFH{E>8J|AB%%_IErp6E_wcxra|`DY zp(mfyNfcLDWIlZuq%@| zy0hVu)=;nGQuS&%wez>40DWtD$tUsIDLPK2^vnW(YD7g}K<*1WrIN=|NezNJdDo6& zMt7CDB-7j9F_jyJ6^uUXG6X)3L<=kp~&A3JVIMxcUksG)&{f#96p;XC!8oj5HXkR=tOP5;A*au z@Bd*wfi2zG%SOJ9`PeQ#1trRhrt=IU+Zh>mo5xu;?(5#p4ZLv_1ONjl6Hx4OgPFCl z9nGfJoQTSw!B#jRD{FQ>gk;N$w+dZ9llM=}dik)ymCUMo%sbHNqeMxqjJYI+-HFW% zu7=f&K4ac`@Q>R5SF8YhClT0`qp<>&YY1JvK3T5Ye4w= zUFFQ~(Hs1h$JQcq9@u+&_=EJOAs1jsFilU;LzaxCVODSO4#MkvOp=n^6@pxpJj`Ja11~=c>LfM zout2_K1}NI%CYJ3_kIQ#3%yqV_Be+1ocwA}sA{Op7D7Ls$@(c-ll{e3vfJPfTl_*m z;~-<=@a)y0RS2Xjw5)qv9MX$3);E5%df|29@o|~6+5nwzc%Q?L2<5M)B@PZ^g6lFo zI9XNZwA%Q4*L}3&LC0VCDUXRdwLmV{+mj84rcT|AmHGU95_%2yt8` z8^#*Dor_=k>!jwNsnJx1m}^bZV#n;g7hQ%Si65MFWK(a_75Su!pJAHcog4FkT?7bt6CKpJl9XuL z08wyMLGDuWgA|4k<5M3ZO$n)F2fvCc)ZmZ7FQl=I@gYl9hkUYZqU}es^4j7>mt~T4 z+&URU@);i)vr(9ZX!W8PAMJU-)04>~&3>ppe0 zoX&NFM=&*PtjZd>$P#(lJK(2u?C7!|h+lUi%_*-Nlq}K}`mV%j_j~+_5(~iUIijt* zN7}f0>Z_1RQyH{0$;71KmpWu%p8j*6KxGd~$KWG7=1nkqoT1Eg6&mRk^Y^t!PYYih zL_Z_tsE~4~Ti*egWfWJkEKEL1gi&N5l+*^kzw$Srl(QFu**UgAHT<=Wr6Zh)i47_= zHk&Uj>DnGwdWDaBYVJJO`TC-|qNbI?W|F|G`p)dEnPQiV0S>kD1NU*vP-m9lSjR**$_0%uO|#Tzwvu#>TVz zM2@l~Dw0NjKlyRQAr@#RdY@=U9bME4_D)0NSO%p=nqDh&T$7qJ_+4g{_>_`gkXP^2 zyr|@SAhoIx^|O$!#{|?AYb|J?J^SLB;Vrf6++)$8V`yRkY>C@8jBp;>o+3Tn?HA=V zGbe!bn>cgYCdI=zmv7}SL%(H)Bre!;N5ZHj^Cx{gjW^vYRPty?9k6UZAn9zbf7P}* zbfjQQ+JQaaVy-TqgC=^Hce$4AC!4sGcJ)ng?{r)=&kTTutK=E{yov`{>MZmVb||0y zDz7_oABU0Kz(W1BR$fQzjGgcG)FDGAYKp5AJSj1t=<;lsjt^dWdNi$pA=Lk)1B?i4v0o9J{n#SMiio6y4**;}2(FBhvqIe~= zR$=6B*BBh+x#znDm(E@k`V*)n0jDkD(Iy_n%k-3>7t@p?&9WD*1|&IL42@;rxFtHe z7+ZxxU$XTs&KsjL4S|ZN!NdN5pqGb;q(CL^7@yb)r_Z8*481XX%9(VRx3Tw|nV_@D zC?ZEWIoN>%C4=C|M({@ z-l0ZcisT*`8i<$Vi`mt1D7gV9h`A(jgmd8P5ksY>$GmW_l!3 z6x!d&gE(s{Gthe>Y03!nd&Zu&(p&*rZNm!q|a)P*Bcsk1VEd)TNorL2^uAv znU?fpIDGt%Pf$_c0)9wLbHog7#L2Hcg)}Yxk3%Pw3pKLrYhFw`c6~_J4EXp5Nmv9; z498C#S02>D>5Yh7+JuI1c5s$%86`qrN&!fH)nVO-XF>o!X}tDrEjQF-zGh%PN|5{c^8uZYY_*31H%t4G%%YG$7~Jt&z9M}TAK2+`liV6R$)>no zcJ8o@`phNjs!`}qL@}iMl9=(4*YQWi0Jli{7+tw=bc+kqS9SwxcZJL0CitAP=x&Dy zeTUBZfyN7w$6BlaaJBPlljyOqp3$J$1bu#yYKm^u2A~*;Y+EsZQvUx&GSr&sCF$St zI#fN(m8RT4w=18|=&fP2@ul>O?V<2CA4kSxm74(4>g6?o9Wf3ZHs0y0s8c8c4tE!7 zs3rE-qz9Qy-RCerCVT?G!sPQu2VH=J@4V zJ1LxNyegI<#|$(BNEr2W?FfKU1xL^V1(uAjY|i**l77C{TM){(tG-3rtLDn-BXOKL z1P>E;KOft0t)Nx{LzA1ON0@!Lr6Aq+MayMj<*!7+=SP*1V!8)Fez(*1pS>DQ#Z8|0 znxI=lx>FzS*6MX{k52iYT=BrhZ5&0fmw+MN*+YGjKf1X!Nb!NO8@+p*GdmAKc97p} zJ=h(ls`v+PO&0@bYoAy4am1l*127^stCo*D-@Y>KUD&AjI#j1?tfi6hkBU6Sfnz_l z%xQ;M>(J49$C}nD&n@|;dt`#0elM^a$ncGt##XhU2$Mt9)Q_-ZU^EqlvfWnV~I#IHNmfa zIG4`^v6#9YExqcjRkYDJCgBpm?eq93`kti&2)M#+O+0c%egPWjm*k}o z_gp|Ij~P7zoo$c>{}=}bF!2UB?Xbd;PR&nkpMcCjKTm~B-P`4wTYUP(?1*{kD*#pt zVR&`v7*iGnfdgHO;!0`>c3q|PGsmMq(sc(GYm+WLau+I^)T3GM6&2hOZ0aHIhv&kM zJY5f-nY z|M0X#Q>zeoy~%A*lUnlFw(bEuoaNPn9Ti>t2pXtKO2=CpbgjSV6|N&$7ajV~;)l6*bj#k=2e}XkCA2nW69HoGSGP&Q~8!Aa85Q z98KW9(7I!T9snHMSm{_{?uWT!DDv#gF%iy-9rR zvA?w127mDvm$N?V8Y=Qbf+xSzIM_i;m6+8RY+`RM4IwDMEb?-{(+!+RW;pKs06%x{T(fJ+x^<+#5M=}h2auveevs^A>VC2zZrGGBf0+%u2n#3%Wo`u zYn&<=DH-8?zW4xBXIcG|<%DZrrW>qHItLRKOmWYvUw^gJmO?Vk=c=2y#n&jgk9STR z0^J^t!y_DrCxQ*M4My=BSh1*uJsHgSB1vkbC-5K&KKZ)Csjuc&ikJ=Afn}7B*QaH$ z0OxpOS08h*Gaa5H-oa2S;F@04RE3xRBulsWIr?i$O`RMiFjQV|EP1pucvOiP&PU0H zB)nr}a(Z&mC|P0=o+1fRgKRT*{4GGlUr9zvnA&Ce#}PSoWr{V%k)vaWpH?E=~2DVfNb^c_8UN&ySe> zQr>_%!N4+-=auBxX1Y2W30d1&;3{^%I~}CBGq?CSscJ<{q*bkIFQHpv1P`kk>rgcu z_7lIp-^(_K2})e-W}l*PvuXtm_YObvV;P(?YAZ8L4v4j;ZMitXBk%vF>yu1VM{ZUn znz$_cB&iBtVSyvpcnjb&h62953)>lqrG}Or8d{mqw`$KpySBfASLg=(cYoQMml^j9 zVZ7oy9fmU3o8L}3P7Z&7q0;u3p|Kpph2n}rGm+oON!260!4yky+-A=7N6#lXcPT}~ za{K#>B{>_>m-_dk`#AoR{EF;Kfp6TnDCXlAOIi7xgFolZswbs*T!z#hHhd7M*U=9Y zCqC~m6@LBNDh?*ShXt1+ml&gp>z_p6#}T+htmmx&o#MB9dTFRyq^hZ?aVgcfqIuk$(gZU0q-11cR9A6|HBe3=3{*c=QMHI6Vs_S@xK`&0kNw z;q^s+f3L&b>AAXBmb#qt$7;t%ZbQ1S7i3p+>B8_>FRq5AhqX(}w+P!eRuVnpVq@c; z3!2O*_&saNC;nnFf7XK-)N?5|pDR)it#?Q&Qc}W(Gl1<6(#*H(s^2%-GBAIAlzVl{ z#xSYaX<>I{)OQ%(!#g+V;;~iz8w~UEuTZNSYF{a07)AQ=1`gV2CQT;JX%fO_t%)4-2r zd5_j4Ap^Z4Nk5*nZ{HBVqVS8!b#=Rciny2WvOSWNcoDhY?FU1_BM}P4aP^(9e9I{; za`xV}$X6>WzwUEfUiy;HRG+w?yIK;xYjL%eJeAQid@~+pRh=@j^1a@Jq(Gj*MvnHe z=tPw>R5-z1&i;?JS;Qfz)${eU)KL4=uOMvB~3*k%Vb z(6e3-CNBZrIB|W%X}*5A);5ho3>L0WVr84LPH_ycE*DI!splsQsOx*@J`cQDO+^t8lT z{p;I-f$(B9Z{8-yrnA+e>>d%Uu>4~B*(&|Q1U1F6$)N+E<1IgrtqB)PUd#Mk+P05d z<*S-mEh5mYvUH~4=?KN*77I=o3o}eVXl@*pR_;AmP;DR6g1Nw2kVnh;_PM2@;H7LNOAe9W&2fxpG8y>K&zE~alCem6*Xc5J4-w8d11_JO!IP6}NQFswFFmMY)#-B5! zXJ*g7YkR)`$EL*w^n^lS2cgs?xE%6iKg44H7y0fcM|`S-VJa9!cFR$y6+wVYVrii0 zA~V1BF&OCQs4aFO4dfI}SoJF~wB5;dJW~JUzEGn9o~&+YF^yjSx>}P;z8dRPztO_z zJ*GU2^e4{3D(?iC%h_0@cY>sO$BO%^R+({BkWmRdU#>0fZe5~*Aa<*d1i6Xxia~{M zK;Pp$gJ%k2gnlyaRx#;${ZKDd{TRK|9bV`^{q{w-VO+zMbA(3K64tv6=c`!gIpA*H zh~PDwfx;-6TuB^=Z^ZA?<$KljLF!Ee(GG*>V)4)Tn&q|67Q+oZ+$)_oVqQFEzMt^v zObz?vG{jDwk!WrXef=z))ZsAp^>>wf7k#lLL`p*fyxKXu*e?`Web8|5_Du1k(pO`w z;j7w{CJu0-z)(w3!)Q+0!SBB@Gev;`k7u`=Ey8FZqA~SxX^RoRVv1(r@g7^nJ&7at z*gZ5;*kxe>BR==3g12aEtdmpu90bl9O=v+dL0~NCQ5Y^LApJ@S8oRP>WAk(6S#h>2 zW7U*{7u#uaaOuWH$r}8b@&KxzEIF5zJ3f!Y}7xSl|!qxpRMczZyM}Mku@jqP)8L$}P>EvOODI4iqic?@6PFKoQm~i98)#FC1P^w;BhSC*K4xB(+P_itOoSX`H6VIRVu-mscdV=IWmv^PV}-jwv$zO^wQA4 z4z`lZ%pqlc+%ph?y)t~u3~ZBSh4f%089=Nq@b6+xC&7Fm|B|6H72F84t|0R&X^#qL zQS}Wj90{YgSCM*5v8D&KQYT$EidEBhA`GS=8f-eD`Wfu1Z`+D55^$vI1*v?4p#0o* znZ$if+-BmL((=qiL%{|kYy=u~bC`1(^`Fo6{)ANKo7UBQa#TpE{x-R}nWQ7tjJDcNlj1$atA{C|Hl2*2nJkqofQUWVoAWIqgh8AhsWg?3 zbKS6dGAROSBs!SZZ9az8ic1Z4h2}bExPYkDq%!4+rOutFxhCl6M@xGMaL1*1oF!M! z#A`;TQKCR&_VtjF7<~?!MT@)vWVX}wA}i!lOC2>En;G!?+ZUE-&ZX?R=R-61uFiWG zH3F~5GS^ED$iDK7jwDDE#>745k-J<9ysQGroickqn{crKs)Rk<6 zPS;$L_%~IxS1K*35B+h0g@f7w-1Tw|`%Z!b8Tu)My$xoU@jScqbZ z`gwRlB8q09K3V5_yqCw9umf6P&#pG0(-Yju#7$xPB763A`^SBy%iFw7Jifh(HD29| zYo8^*+5b6KmS(@TI|;@!pF(5xB%d=#m3(*6m>TXa7O)9%d2%1gq*?}~>^ru}*PGbI zd@$hwxJhQ`J6KSqL1Cdz8LqZYp;;IrY*1r-(z9!gL1_z&TcEk#FodI<3D|Iup$zR$ z6*V}4dU@ztOq4TB9WWMqOI%~$w4H_+8j8kLuZ1(o&upF>h1zswjyFCb(bVx zRHn^MO5xT6?u7H873>D*7(Wq6yQZtVVJKcuI{|oanRn@4#9oyL=uGK@`VRcoV%Q=31=3qUWvGsripjp%_pk?r;QZYk4MywuKPlk1$WUf@#M!CFu8K3qI(r%C zN!I1xZpHee3A!gf~x%)|vFCEd#1VKVTxdtASEQoWF zXbGcAI+HnlZ#Tp6vP5w{cY((aj5%~+@qPji9Uh+%B#`yPH{aJFI-nxN@byWD zmmsz`;&q%)9;kn*gj2Tf%x4d2xfTgcBtoY~;^TcoitQSI>W*-MZC1`di149nRpV{vPX5Noz8f{iM%3RoTNp zF@H7K18a8>5WcDTNaD z1#B7&d3rZ`tMBCJi@#@X*)HRfKG1@M7}7(Sc56&#DxEVIz%{x1TUdC1EQc?Sz(b9! z4v676X^3$6P*wU%{qtp3x-Q1sIVI1-c@xkHs3F@L%w) zZH6PE{9;%~Eejjm1;3^4{{WX5JYeaN8#jjsgju2O5?wbcDW^7C0ko+Rv z&6b<{+xFy~4oRWAC$m+*xS&>JWP_fj20<{utjtw8kUwexl<9G$9zg|%bROWXW#`i} z2$_}aOhm)@xDPXI-Cch+gkS$4gH4s!4|{D^4P^| z$KC@00@HtJc!#%{wbg%(QX-CTRTJw(-J51)G1*qg$7)Hnk(l*Q@0Al7+DMr0+E_c` z#dMKw0;fwah&>b>k(b@tcLZd*aCj?O4D8?Wt=r?wC*)FgmcLP9Wr2u|&&K3m6D%yt zcn`1IYvL#tIpoYv5Q#|)P)gPDOo3&st{Lch;pgB((3v0Aqkq73kamXm&WDU16yk8zc{#(WQ0cr%! zId`}7uFp3D{SEo#o{WwFa!h8QZ``r6vO|9SS|`(j{f=H#v=he1GS?Pz+~D(7kXBA^ z#$fNmx420+#axvX3T{hUGG{><=Yg`O7I2+&y+ANdpgak%d@=E7uEmJ6tr?L7?JI(s z+~=U*-q^ma+M~v$3}%!1YbBBP&&qt!1e&iR15i)D3_UOczRdGB7Nb*lpHuAMwhUi# ziMSp%B(%|Gjfcbu6doHx8^7e@VPjM#jME>DS@n3Xw%~swFp=e4s#6$I-Ty|5%XXBr z$q%&HDo3?azRXSN46;YV%-(i~ys|3s`Y#cAee`*7{q#1^@c6|=^h)F?0I@p$>5t zsep&Ye3yGk=40|&Vc`lV1?ptaeHBFqcDeTzo_2}z^?8#F{j*0}fRo==&=9DlX_r~O z(cCv4Zz_2t-|>{-dD-{+o#TPatxZ8cRpT?NY&;H@4-QJC`nQ=lgK3C>j~&9(2|JMJ zmHCI3zu2jWw8K4HWa%J!8K07LR&nsPjEFmVo4mWZeN0NQuKw1MUo0A5s{Dsb2Ki*< zgA2c|XX?mJ8SPs9?q=#Zr*F;rfB<f@hwxK^rGFK>Q_b1)PGY0Rk}~oM+sH9{gmLm`SG%XOHc_Ab%9EA_*b3JW z?}gK|=i|pk$%Q&W@(I@O?^`MPypIbgwes<hsOK^f(8Ai{}Eeo{2 z#Q%Xsr3u*>mOPTd*|WGj>s-Rp@F~M>?k$Yl zkK0&V(v|$D((c$;PK1<|Cwi(6-x84|E<=n*|C&vs%p{vSd#H1#Bb)i+>M&&f;+uri zBO7iRu0p>41GQ@uQ}}X)29!Xr%MNjlKCr-0^5-)R6Km>xOpvn!w-8x&eJ3d|P@48k zs0erLiP>U^ZQ0V=LLio;cE*PGlaCM63Q69xWam!_L$51sLx@DIXMAGS>4>Z-F>Gvi z1{7kvpNTE@CfmTLN0MsKKODJ-o@qBDVQrJ}5F(6L@#^xPk=9%2$_s88Qns!ujwexE zaR&z4_cA0w6rlUHOAnHLLyxOD6o5?NY&^Aft&lg^q#@Nqwxs%eZ;aU*^d-Hmy>I5U zpmzk9fkOx9}K-0qd+>x~tUf;Z0lq*x(tZs2XZAlJ; z;XSKP%Uvl<8!+i1G9L(~>^;2rcbR#dP!ddk{ZrgA?cu;%M;}xpOmqP&xTh97C3fn(ft%5QTbk#Y&~CBSi383{LQ z%hILPM;jCO9&QOG-c({p4JjETqY_UB-1yYqZn`Kpjy7yIgZG5&77^(!=mC030*eB(WV`DhTEoh*}Z9D7Znu5xy^u2wWu-Ebyq{ zdJ#0KxPf2%WS2M8z2Y-)qKq}@^HacvdEt5o*ywu^139+ZIR99(yW-N2yycnX+S^f= z0|POrVIB3Us#gq^xA}KTR&t2^nQ63yMXKM>|6gE*- za}v>3rU}`+ExmwlZL5$@8!=^({Xep@ZXzf9CCxPyaXN1myEqogOOab8Sy3VE;%<&q zV(MlJ8gSunV96Ro9;WBQ7CT;kSU#>ol|E*N52=B9?+2XkVMpX5M{Dqd4i-Dt_;g%t zs_-**-hM{N;vIPC6xI2rF14u@Ljr%O6dT1KrGo-Yd`l#s>|rwZb)riDeBV&Ia4fZO zghTAStq43*dY9u=MypD-PHsy@gxVPHOiDQl?9mw*z$%`DdV8w_lb6unWt0I<#1XoGHHS_9-MkH zsGODVv}k|4mOH4((0Q1`M%#o2bIs`R`oEp+YCCF@NATIBf|M=>;-*-HnRBCO)3i|EJ>X@y0Kr~bhjV5X_F zP7tHa0aMe&ewAI@?ay9i@~Rt;#H3G!T~nCf9p1LCq2Y9b2;vNHd=S}WlCMNKyUmB^ zSFDe94mG!}^@k7Dy4-45(X^F&X}X}S!g=^T{;Pve?fJFKUby@jP7#zr_32lnv@7K{KRy64)4 z1BMkg$(`=nQ_x(YUp2oFt33`Kf7BbUUN$Z^OI6X+kT{r&wO5nH?fftrVi4%|Lxlk8 z7FGzimZ`Z*(1#WD0p8~qzgIF4AZKWWjZ8eZpUC0SKChUw>OJdd{H&#>q5594V$s_H zmB;ppb2ZnMBH#3H&Pc)xeh8IrL-Zx#)?^7?TD|02l}qUR8k0O~q_=4vugG3u!{jmO z%vZFYPEP(;mhx->;KOaQ-a2^!hziC_eajiNvB2U!jX1b~AT1t-Ykk|0{8U8eA z!?f{j(qI01W|U*2BiKMW-4RIIbLsX!!wrK3rJCh*Fw@5lMU;(+#jR8Bdn_O(j$XKK z@W<`Psqb#z%3)d9DrI{{Ey|DIu{nH)Q*4KGtzcn2G}L;!gp?nlE%v<~NHT-1lM}*f z73@+b!!(hrqgfFpZ%zJE5yIxxEhTvTWi6NY;BFXhI<1e!PeksVJvYe4K`^%&VUGe6 zDY()7_%rEmS3Hexx2Je)59l>dzfOC}>J<9hw-PGsLzuT~U<0;gYRHdIL8)dGyZQz6 zGjs_m;cNF~q}G?<$0{3Ys++#q_A&90&1I+6OH<>|l2Pvu z4f<3q*4nu&;xjwQA8?^QCF`XDmClMoS7s7Bn7R4TpmG!sUsuCA)$(hs z?R}#te)Z7BmsTQUpKe1>Jn7HAdPzy~lF)}p#hri1$m+{POj;OTLl_BzVsZqGOb*YP zJ^J2cdN@(tR7BDIt9o3j`ju0|zEFbimQ}kh>khzeZE-kbq_b|ESdD&D0MqsFE*mP# zxPaH{ZofENcBkt@<80>V_~>}1-cA9a%4FMeTPnN-cugkCN-X{zSejr)(o)~b7x4+( zWWONEMm09~;*COc>nun88e6XV$3nvFo=}(NqKF)3o!E=6a^QETm=pUe(>@OluGnf5 zs08t)GDzbkAE^Jp0f641lMz}Lsd{mvny079eHqKu!rXfS;0($vKY$LB{VM)!;?8Q+ z4~Q~jwUEB|H$kX%N-s7jP#=SN0q9$uX$TUMc|qQ{u@p18iHff8i_-7HH`Hz1h(&4q zcz%6Lqun>hsWtv3V5Kt})RBpnIq5IVCi|V{a1c&+BBb^q`^GA=9)m2-ZagC|TM~R{ zgqx@vdnVXjy^m?kGuZF3GSWqdRIh03ZyhsGcdlI8)tf)q6@MM)e$MJkrfDC4T^}Sp z(x+VP0pwJhNb~_%pRQ}n&!xa6C0ZaAx3@?QS!jl=o7xg5XQ=@2{o^>7u(d4&nTycq z)KYzJ?jMHhPq5hB$kxj2^gD1upLZ6iizs01J!luQ(`_VCgZ0AprC|r>_({&qgib@27W}OR?|9WJem`UBsMc1E89<^ zU-Ii1KvxH=E^0~aj@9zysNMi)c-z`zya7j=5cH`-m37q{EL+#XI&<06VQ!~6^-U`* zJb;Y%OuBFsOJo7%&%wr{dRx_b>oeFrKMM#go`V%vtCZ`7Nd?R?6jQjVJmp=~;XXsx zdzLQ(o(1lA4fsYNN?dE_Xq>Qh<1H`@bhN);@)V>4YTZ3qJMW$yTkq%Y5|L4dI!b+& z+?u&xUyY4JKa-J)1vxLQCxP(al`d}V!7rEeo}F#V(dyiox9ZlLpG~D8)Z4WJzOT5k zmOsq~NbeLdJA4qGM4?y;YDcX1!x1|RtCo8@^!K`}6qYnNX`VuJQRjcve{7`9)An){tCEq!C(7$l01x99v6mSkR;|KLkkhuBJHb~Cl8K94Bjk;2AVC`Cw7;1~{(%PmX= zl_(o+!M2+6vn&{!t`0d%Bfa(5Nap&*q|aLcH7DU89o{dn43^DA1|P=^Cw3?+3=}>Ef$Y2a;>ok2zTtTpw0qaHMs2f=u=SN2aQ)O7gs#_+>FV;5 z7Sba8>vy5+j`p~8&>s&omv}=8<_I#uHgl9H^wzF3IC!k;KE|Q=j18Pi-_R=NAnR8v z^u_^@&)u36qc(;5y%Jl`T`qC3QXcckFlu*VsS9O2*`oS2%=efQah z_bwJ0r}XMa4AijYG8<)3vmQ6t>`~B9LxpvJAx5f+oejoS9a|a1>a_xAX9-M{)(vpW z$@G$$YiGO8hv^dQd1Qkc`09W>m3`(d*~Ds|m4C94HOmB5C?U>;S|!-yOX%lsnuu z_mhQw1OOG->mlOeh~zEt8r`NfGv5wB^Tm_rnt2c08RfHO?%f~w3H4u_!TTg&vW70E zJEww86<~7bOk}X!jcJZpMPgQ_r-N^8Po3;~DAD7Lg#Jja`?7$pulNOt3GFe=AB1z2 z!H!<+!|=;3>bk1s82ld`dL|Bf#J|Ip9b;FhNtXnkAUvW}wH;jfboxYz(#^A@;+b8n zST&`J!B3l; zJhv%}&D-Q(Nsvedr=!MMnqL2bW{D_<&L08hwAd&oplQ&%MN&tXEWp9FL_fuh3sIN2 zGbChoYK>%UtER`^rk*XkhR_r_x+Dwcm@H6|2u4(eFfgDRV6*DaQ4|e>lLOvz zhA!>`QPwJ*oms*G0wtfj4?{_bcyLCYDwUcubFRsL( zC$atZjiZM;AjDV0=6T?EiWF@gg%DQHxei_s2-*K7wfs?AvCSHb;UhBMbbM0yXGxOp zan%B4Z2RUT;^4ilciAfBxG|qfT0VW8X(wqz-iPE5CbWQ#7{ZFgexX$%9fl0Vuv4?D z@#oONyN)|3H;*lGV}u$rP|GeFPtHfO#43QJjS#Mu!FP^+d-IhD z+(Ha6%N|fV$Oia~2XxMTh7>7ft9$uwA;-FXXZAJyu+3a=7K@|%*xECyeTJR_F6uvF zSE!TLnZYMG)jBAg2!T~G^itCmUc-X&o_Tv_*ATT2q5AX}*$G(j{${jr?XnR$W9@_E z6SBcpA^0ft=-G#w++jP^pKG${p}cPFiX*CNE_#@!+2!9G#eKJyHcaCAf!%&RS$2Z{ zDgJX!v)-QId#vS|>s$Ods86K8edXvEDTND2Bi5-U<0CP$m=e2NwXc%zuR|Q~#w|(Y z9|AA{P4$& zw>LRZQlj*^y{eZU_Um)KREQeYoqaya1mKP=t!9Socf$`K0#>#leICl~RSv|*>V<8s zEyX3al36ZQZHw!it!ngFk?8n%bf#mi;Sf`LFt9O~x^>DP=NMsUr%I6q!#g*H90Zjs zy?N`wQ1nzkx#&)bYv7BZJM@sxDD>2jCcdsG=t7L;dEdk!gfxB%NoKouKT9}SlSX`? zm8mp)JY}5FuDWC=AV?8<0>SSU6t4Xs6g9Oj8aEXU_KmQ6IfpuMf+{h;kcn_|sOD0n ziP6fpy3FW+S>R3qLE(ck#kxEF(Mhwjz1x2bU0MY=kq(@k$aU@ZNGG!}SFuxu;XC+y zO6(OT#9kXS4F4)^;?h2r-HX=2#!*IZ-rp0!cxvc)h8xkjf=4Z@)x-F$Y##wsaj|3a zBU9sldbu_^Jz(K3;`A+VxN8FBN5ufBC6s{;P}a{xdCqLg##&3D_))(`-(&xk+_y0z`el5sYZ*PPU&?iih63u)610?>l z&sRkWO~2`HA1baTz8B1t$EzWoVKux4LZ7E z;FoC?_c9X@Sf}R}vLj+!-03p+_ zh?{Qf^;|JeVhNl@hw1V^dj-aG)`+CiyNyvw9MXpA|2j$#BN&k&Z*kK5a&D&Q%8SYh zDZ~`WzKs8^AAiYu9bUAW=U`ejbI>8Pe&(%%dPisHczGCSlS+I%D8`tD|6k{tBGknn xk%iUyK0^FSz0hLOEd7yeagv1pi)bhpbufzlg|e8owuApOxoUm|bIB$0zW}ov4_*KO literal 0 HcmV?d00001