diff --git a/CMakeLists.txt b/CMakeLists.txt index a5c4fe930..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") @@ -421,6 +421,7 @@ if (TOOLS) add_subdirectory(rlp) add_subdirectory(abi) + add_subdirectory(ethvm) add_subdirectory(eth) if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug") 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/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 8cde476c3..e88086e0d 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); @@ -209,7 +210,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 +229,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); @@ -240,6 +247,10 @@ Main::Main(QWidget *parent) : #if !ETH_FATDB removeDockWidget(ui->dockWidget_accounts); +#endif +#if !ETH_EVMJIT + ui->jitvm->setEnabled(false); + ui->jitvm->setChecked(false); #endif installWatches(); startTimer(100); @@ -805,6 +816,7 @@ void Main::readSettings(bool _skipGeometry) ui->usePrivate->setChecked(m_privateChain.size()); ui->verbosity->setValue(s.value("verbosity", 1).toInt()); ui->jitvm->setChecked(s.value("jitvm", true).toBool()); + on_jitvm_triggered(); ui->urlEdit->setText(s.value("url", "about:blank").toString()); //http://gavwood.com/gavcoin.html on_urlEdit_returnPressed(); @@ -1240,9 +1252,15 @@ void Main::refreshBlockCount() { auto d = ethereum()->blockChain().details(); BlockQueueStatus b = ethereum()->blockQueueStatus(); - HashChainStatus h = ethereum()->hashChainStatus(); - ui->chainStatus->setText(QString("%9/%10%11 hashes %3 ready %4 verifying %5 unverified %6 future %7 unknown %8 bad %1 #%2") - .arg(m_privateChain.size() ? "[" + m_privateChain + "] " : "testnet").arg(d.number).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/alethzero/OurWebThreeStubServer.cpp b/alethzero/OurWebThreeStubServer.cpp index 7e9836818..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()), + 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/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake index eb8588ceb..53535a489 100644 --- a/cmake/EthCompilerSettings.cmake +++ b/cmake/EthCompilerSettings.cmake @@ -21,7 +21,7 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DETH_DEBUG") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG -DETH_RELEASE") set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG -DETH_RELEASE") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_DEBUG") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DETH_RELEASE") if ("${CMAKE_SYSTEM_NAME}" MATCHES "Linux") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++ -fcolor-diagnostics -Qunused-arguments -DBOOST_ASIO_HAS_CLANG_LIBCXX") diff --git a/eth/main.cpp b/eth/main.cpp index 5497a2cda..4b23ef62a 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -93,6 +93,7 @@ void interactiveHelp() << " accounts Gives information on all owned accounts (balances, mining beneficiary and default signer)." << endl << " newaccount Creates a new account with the given name." << endl << " transact Execute a given transaction." << endl + << " transactnonce Execute a given transaction with a specified nonce." << endl << " txcreate Execute a given contract creation transaction." << endl << " send Execute a given transaction with current secret." << endl << " contract Create a new contract with current secret." << endl @@ -108,6 +109,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; @@ -124,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 @@ -286,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; @@ -597,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") @@ -679,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, @@ -806,14 +812,14 @@ 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) - for (auto const& i: Host::pocHosts()) - web3.requirePeer(i.first, i.second); - if (remoteHost.size()) - web3.addNode(p2p::NodeId(), remoteHost + ":" + toString(remotePort)); + 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 ETH_JSONRPC || !ETH_TRUE shared_ptr jsonrpcServer; @@ -821,11 +827,22 @@ 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(); + 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); @@ -965,8 +982,13 @@ 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(); + 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") { @@ -1175,6 +1197,75 @@ int main(int argc, char** argv) else cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET DATA"; } + + else if (c && cmd == "transactnonce") + { + auto const& bc =c->blockChain(); + auto h = bc.currentHash(); + auto blockData = bc.block(h); + BlockInfo info(blockData); + if (iss.peek() != -1) + { + string hexAddr; + u256 amount; + u256 gasPrice; + u256 gas; + string sechex; + string sdata; + u256 nonce; + + iss >> hexAddr >> amount >> gasPrice >> gas >> sechex >> sdata >> nonce; + + if (!gasPrice) + gasPrice = gasPricer->bid(priority); + + cnote << "Data:"; + cnote << sdata; + bytes data = dev::eth::parseData(sdata); + cnote << "Bytes:"; + string sbd = asString(data); + bytes bbd = asBytes(sbd); + stringstream ssbd; + ssbd << bbd; + cnote << ssbd.str(); + int ssize = sechex.length(); + int size = hexAddr.length(); + u256 minGas = (u256)Transaction::gasRequired(data, 0); + if (size < 40) + { + if (size > 0) + cwarn << "Invalid address length:" << size; + } + else if (gas < minGas) + cwarn << "Minimum gas amount is" << minGas; + else if (ssize < 40) + { + if (ssize > 0) + cwarn << "Invalid secret length:" << ssize; + } + else + { + try + { + Secret secret = h256(fromHex(sechex)); + Address dest = h160(fromHex(hexAddr)); + c->submitTransaction(secret, amount, dest, data, gas, gasPrice, nonce); + } + catch (BadHexCharacter& _e) + { + cwarn << "invalid hex character, transaction rejected"; + cwarn << boost::diagnostic_information(_e); + } + catch (...) + { + cwarn << "transaction rejected"; + } + } + } + else + cwarn << "Require parameters: submitTransaction ADDRESS AMOUNT GASPRICE GAS SECRET DATA NONCE"; + } + else if (c && cmd == "txcreate") { auto const& bc =c->blockChain(); @@ -1403,6 +1494,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/ethminer/CMakeLists.txt b/ethminer/CMakeLists.txt index 3ec92fc14..df828bc47 100644 --- a/ethminer/CMakeLists.txt +++ b/ethminer/CMakeLists.txt @@ -22,6 +22,10 @@ target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES}) if (JSONRPC) target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_CLIENT_LIBRARIES}) + target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES}) + if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) + eth_copy_dlls(${EXECUTABLE} CURL_DLLS) + endif() endif() target_link_libraries(${EXECUTABLE} ethcore) diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 245b97ceb..6de3913e4 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -97,11 +98,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 +111,7 @@ public: } else if (arg == "--opencl-platform" && i + 1 < argc) try { - openclPlatform = stol(argv[++i]); + m_openclPlatform = stol(argv[++i]); } catch (...) { @@ -119,8 +120,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,21 +129,20 @@ public: throw BadArgument(); } else if (arg == "--list-devices") - { - ProofOfWork::GPUMiner::listDevices(); - exit(0); - } - else if (arg == "--use-chunks") - { - dagChunks = 4; - } + 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 == "--force-single-chunk") + m_forceSingleChunk = 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; @@ -151,7 +151,7 @@ public: } else if (arg == "--benchmark-warmup" && i + 1 < argc) try { - benchmarkWarmup = stol(argv[++i]); + m_benchmarkWarmup = stol(argv[++i]); } catch (...) { @@ -160,7 +160,7 @@ public: } else if (arg == "--benchmark-trial" && i + 1 < argc) try { - benchmarkTrial = stol(argv[++i]); + m_benchmarkTrial = stol(argv[++i]); } catch (...) { @@ -169,7 +169,7 @@ public: } else if (arg == "--benchmark-trials" && i + 1 < argc) try { - benchmarkTrials = stol(argv[++i]); + m_benchmarkTrials = stol(argv[++i]); } catch (...) { @@ -179,21 +179,12 @@ public: else if (arg == "-C" || arg == "--cpu") m_minerType = MinerType::CPU; else if (arg == "-G" || arg == "--opencl") - { - if (!ProofOfWork::GPUMiner::haveSufficientMemory()) - { - 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 == "--current-block" && i + 1 < argc) + m_currentBlock = stol(argv[++i]); else if (arg == "--no-precompute") { - precompute = false; + m_precompute = false; } else if ((arg == "-D" || arg == "--create-dag") && i + 1 < argc) { @@ -201,7 +192,7 @@ public: mode = OperationMode::DAGInit; try { - initDAG = stol(m); + m_initDAG = stol(m); } catch (...) { @@ -251,7 +242,7 @@ public: else if ((arg == "-t" || arg == "--mining-threads") && i + 1 < argc) { try { - miningThreads = stol(argv[++i]); + m_miningThreads = stol(argv[++i]); } catch (...) { @@ -266,21 +257,36 @@ public: void execute() { + 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::setDefaultPlatform(openclPlatform); - ProofOfWork::GPUMiner::setDefaultDevice(openclDevice); - ProofOfWork::GPUMiner::setNumInstances(miningThreads); - ProofOfWork::GPUMiner::setDagChunks(dagChunks); + ProofOfWork::GPUMiner::setNumInstances(m_miningThreads); + if (!ProofOfWork::GPUMiner::configureGPU( + m_openclPlatform, + m_openclDevice, + m_clAllowCPU, + m_extraGPUMemory, + m_forceSingleChunk, + m_currentBlock + )) + { + 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) @@ -311,7 +317,11 @@ 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 - << " --use-chunks When using GPU mining upload the DAG to the GPU in 4 chunks. " << 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 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/ethvm/CMakeLists.txt b/ethvm/CMakeLists.txt new file mode 100644 index 000000000..ed093061c --- /dev/null +++ b/ethvm/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_policy(SET CMP0015 NEW) +set(CMAKE_AUTOMOC OFF) + +aux_source_directory(. SRC_LIST) + +include_directories(BEFORE ..) +include_directories(${LEVELDB_INCLUDE_DIRS}) + +set(EXECUTABLE ethvm) + +add_executable(${EXECUTABLE} ${SRC_LIST}) + +target_link_libraries(${EXECUTABLE} ethereum) + +if (APPLE) + install(TARGETS ${EXECUTABLE} DESTINATION bin) +else() + eth_install_executable(${EXECUTABLE}) +endif() diff --git a/ethvm/main.cpp b/ethvm/main.cpp new file mode 100644 index 000000000..08a1b4508 --- /dev/null +++ b/ethvm/main.cpp @@ -0,0 +1,200 @@ +/* + 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 main.cpp + * @author Gav Wood + * @date 2014 + * EVM Execution tool. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; +using namespace dev; +using namespace eth; + +void help() +{ + cout + << "Usage ethvm [trace|stats|output] (|--)" << endl + << "Transaction options:" << endl + << " --value Transaction should transfer the wei (default: 0)." << endl + << " --gas Transaction should be given gas (default: block gas limit)." << endl + << " --gas-price Transaction's gas price' should be (default: 0)." << endl + << " --sender Transaction sender should be (default: 0000...0069)." << endl + << " --origin Transaction origin should be (default: 0000...0069)." << endl +#if ETH_EVMJIT || !ETH_TRUE + << endl + << "VM options:" << endl + << " -J,--jit Enable LLVM VM (default: off)." << endl + << " --smart Enable smart VM (default: off)." << endl +#endif + << endl + << "Options for trace:" << endl + << " --flat Minimal whitespace in the JSON." << endl + << " --mnemonics Show instruction mnemonics in the trace (non-standard)." << endl + << endl + << "General options:" << endl + << " -V,--version Show the version and exit." << endl + << " -h,--help Show this help message and exit." << endl; + exit(0); +} + +void version() +{ + cout << "ethvm version " << dev::Version << endl; + cout << "By Gav Wood, 2015." << endl; + cout << "Build: " << DEV_QUOTED(ETH_BUILD_PLATFORM) << "/" << DEV_QUOTED(ETH_BUILD_TYPE) << endl; + exit(0); +} + +enum class Mode +{ + Trace, + Statistics, + OutputOnly +}; + +int main(int argc, char** argv) +{ + string incoming = "--"; + + Mode mode = Mode::Statistics; + State state; + Address sender = Address(69); + Address origin = Address(69); + u256 value = 0; + u256 gas = state.gasLimitRemaining(); + u256 gasPrice = 0; + bool styledJson = true; + StandardTrace st; + + for (int i = 1; i < argc; ++i) + { + string arg = argv[i]; + if (arg == "-h" || arg == "--help") + help(); + else if (arg == "-V" || arg == "--version") + version(); +#if ETH_EVMJIT + else if (arg == "-J" || arg == "--jit") + VMFactory::setKind(VMKind::JIT); + else if (arg == "--smart") + VMFactory::setKind(VMKind::Smart); +#endif + else if (arg == "--mnemonics") + st.setShowMnemonics(); + else if (arg == "--flat") + styledJson = false; + else if (arg == "--value" && i + 1 < argc) + value = u256(argv[++i]); + else if (arg == "--sender" && i + 1 < argc) + sender = Address(argv[++i]); + else if (arg == "--origin" && i + 1 < argc) + origin = Address(argv[++i]); + else if (arg == "--gas" && i + 1 < argc) + gas = u256(argv[++i]); + else if (arg == "--gas-price" && i + 1 < argc) + gasPrice = u256(argv[++i]); + else if (arg == "--value" && i + 1 < argc) + value = u256(argv[++i]); + else if (arg == "--value" && i + 1 < argc) + value = u256(argv[++i]); + else if (arg == "stats") + mode = Mode::Statistics; + else if (arg == "output") + mode = Mode::OutputOnly; + else if (arg == "trace") + mode = Mode::Trace; + else + incoming = arg; + } + + bytes code; + if (incoming == "--" || incoming.empty()) + for (int i = cin.get(); i != -1; i = cin.get()) + code.push_back((char)i); + else + code = contents(incoming); + bytes data = fromHex(boost::trim_copy(asString(code))); + if (data.empty()) + data = code; + + state.addBalance(sender, value); + Executive executive(state, eth::LastHashes(), 0); + ExecutionResult res; + executive.setResultRecipient(res); + Transaction t = eth::Transaction(value, gasPrice, gas, data, 0); + t.forceSender(sender); + + unordered_map> counts; + unsigned total = 0; + bigint memTotal; + auto onOp = [&](uint64_t step, Instruction inst, bigint m, bigint gasCost, bigint gas, VM* vm, ExtVMFace const* extVM) { + if (mode == Mode::Statistics) + { + counts[(byte)inst].first++; + counts[(byte)inst].second += gasCost; + total++; + if (m > 0) + memTotal = m; + } + else if (mode == Mode::Trace) + st(step, inst, m, gasCost, gas, vm, extVM); + }; + + executive.initialize(t); + executive.create(sender, value, gasPrice, gas, &data, origin); + boost::timer timer; + executive.go(onOp); + double execTime = timer.elapsed(); + executive.finalize(); + bytes output = std::move(res.output); + + if (mode == Mode::Statistics) + { + cout << "Gas used: " << res.gasUsed << " (+" << t.gasRequired() << " for transaction, -" << res.gasRefunded << " refunded)" << endl; + cout << "Output: " << toHex(output) << endl; + LogEntries logs = executive.logs(); + cout << logs.size() << " logs" << (logs.empty() ? "." : ":") << endl; + for (LogEntry const& l: logs) + { + cout << " " << l.address.hex() << ": " << toHex(t.data()) << endl; + for (h256 const& t: l.topics) + cout << " " << t.hex() << endl; + } + + cout << total << " operations in " << execTime << " seconds." << endl; + cout << "Maximum memory usage: " << memTotal * 32 << " bytes" << endl; + cout << "Expensive operations:" << endl; + for (auto const& c: {Instruction::SSTORE, Instruction::SLOAD, Instruction::CALL, Instruction::CREATE, Instruction::CALLCODE, Instruction::MSTORE8, Instruction::MSTORE, Instruction::MLOAD, Instruction::SHA3}) + if (!!counts[(byte)c].first) + cout << " " << instructionInfo(c).name << " x " << counts[(byte)c].first << " (" << counts[(byte)c].second << " gas)" << endl; + } + else if (mode == Mode::Trace) + cout << st.json(styledJson); + else if (mode == Mode::OutputOnly) + cout << toHex(output); + + return 0; +} diff --git a/evmjit/libevmjit-cpp/JitVM.cpp b/evmjit/libevmjit-cpp/JitVM.cpp index 0d6a6e00a..68161526d 100644 --- a/evmjit/libevmjit-cpp/JitVM.cpp +++ b/evmjit/libevmjit-cpp/JitVM.cpp @@ -51,7 +51,7 @@ bytesConstRef JitVM::execImpl(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _on m_data.timestamp = static_cast(_ext.currentBlock.timestamp); m_data.code = _ext.code.data(); m_data.codeSize = _ext.code.size(); - m_data.codeHash = eth2llvm(sha3(_ext.code)); + m_data.codeHash = eth2llvm(_ext.codeHash); auto env = reinterpret_cast(&_ext); auto exitCode = m_engine.run(&m_data, env); diff --git a/evmjit/libevmjit/Array.cpp b/evmjit/libevmjit/Array.cpp index 3266038db..0b511a058 100644 --- a/evmjit/libevmjit/Array.cpp +++ b/evmjit/libevmjit/Array.cpp @@ -9,8 +9,6 @@ #include "Runtime.h" #include "Utils.h" -#include // DEBUG only - namespace dev { namespace eth @@ -269,52 +267,15 @@ void Array::extend(llvm::Value* _arrayPtr, llvm::Value* _size) } } -namespace -{ - struct AllocatedMemoryWatchdog - { - std::set allocatedMemory; - - ~AllocatedMemoryWatchdog() - { - if (!allocatedMemory.empty()) - { - DLOG(mem) << allocatedMemory.size() << " MEM LEAKS!\n"; - for (auto&& leak : allocatedMemory) - DLOG(mem) << "\t" << leak << "\n"; - } - } - }; - - AllocatedMemoryWatchdog watchdog; -} - extern "C" { - using namespace dev::eth::jit; - EXPORT void* ext_realloc(void* _data, size_t _size) noexcept { - //std::cerr << "REALLOC: " << _data << " [" << _size << "]" << std::endl; - auto newData = std::realloc(_data, _size); - if (_data != newData) - { - DLOG(mem) << "REALLOC: " << newData << " <- " << _data << " [" << _size << "]\n"; - watchdog.allocatedMemory.erase(_data); - watchdog.allocatedMemory.insert(newData); - } - return newData; + return std::realloc(_data, _size); } EXPORT void ext_free(void* _data) noexcept { std::free(_data); - if (_data) - { - DLOG(mem) << "FREE : " << _data << "\n"; - watchdog.allocatedMemory.erase(_data); - } } - -} // extern "C" - +} diff --git a/evmjit/libevmjit/Cache.cpp b/evmjit/libevmjit/Cache.cpp index 47a6386e9..42ccf44ac 100644 --- a/evmjit/libevmjit/Cache.cpp +++ b/evmjit/libevmjit/Cache.cpp @@ -1,5 +1,7 @@ #include "Cache.h" +#include + #include "preprocessor/llvm_includes_start.h" #include #include @@ -23,6 +25,8 @@ namespace jit namespace { + using Guard = std::lock_guard; + std::mutex x_cacheMutex; CacheMode g_mode; llvm::MemoryBuffer* g_lastObject; ExecutionEngineListener* g_listener; @@ -43,6 +47,9 @@ namespace ObjectCache* Cache::getObjectCache(CacheMode _mode, ExecutionEngineListener* _listener) { static ObjectCache objectCache; + + Guard g{x_cacheMutex}; + g_mode = _mode; g_listener = _listener; return &objectCache; @@ -50,6 +57,8 @@ ObjectCache* Cache::getObjectCache(CacheMode _mode, ExecutionEngineListener* _li void Cache::clear() { + Guard g{x_cacheMutex}; + using namespace llvm::sys; llvm::SmallString<256> cachePath; path::system_temp_directory(false, cachePath); @@ -62,6 +71,8 @@ void Cache::clear() void Cache::preload(llvm::ExecutionEngine& _ee, std::unordered_map& _funcCache) { + Guard g{x_cacheMutex}; + // TODO: Cache dir should be in one place using namespace llvm::sys; llvm::SmallString<256> cachePath; @@ -92,11 +103,14 @@ void Cache::preload(llvm::ExecutionEngine& _ee, std::unordered_map Cache::getObject(std::string const& id) { + Guard g{x_cacheMutex}; + if (g_mode != CacheMode::on && g_mode != CacheMode::read) return nullptr; - if (g_listener) - g_listener->stateChanged(ExecState::CacheLoad); + // TODO: Disabled because is not thread-safe. + //if (g_listener) + // g_listener->stateChanged(ExecState::CacheLoad); DLOG(cache) << id << ": search\n"; if (!CHECK(!g_lastObject)) @@ -136,12 +150,15 @@ std::unique_ptr Cache::getObject(std::string const& id) void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) { + Guard g{x_cacheMutex}; + // Only in "on" and "write" mode if (g_mode != CacheMode::on && g_mode != CacheMode::write) return; - if (g_listener) - g_listener->stateChanged(ExecState::CacheWrite); + // TODO: Disabled because is not thread-safe. + // if (g_listener) + // g_listener->stateChanged(ExecState::CacheWrite); auto&& id = _module->getModuleIdentifier(); llvm::SmallString<256> cachePath; @@ -161,6 +178,8 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module) { + Guard g{x_cacheMutex}; + DLOG(cache) << _module->getModuleIdentifier() << ": use\n"; auto o = g_lastObject; g_lastObject = nullptr; 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/libdevcore/Common.cpp b/libdevcore/Common.cpp index 3dc3fd280..22ea584c1 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -28,7 +28,7 @@ using namespace dev; namespace dev { -char const* Version = "0.9.24"; +char const* Version = "0.9.26"; const u256 UndefinedU256 = ~(u256)0; diff --git a/libdevcore/Common.h b/libdevcore/Common.h index 453c17e6f..1ee83c794 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -181,7 +181,7 @@ private: /// Scope guard for invariant check in a class derived from HasInvariants. #if ETH_DEBUG -#define DEV_INVARIANT_CHECK ::dev::InvariantChecker __dev_invariantCheck(this) +#define DEV_INVARIANT_CHECK { ::dev::InvariantChecker __dev_invariantCheck(this); } #else #define DEV_INVARIANT_CHECK (void)0; #endif diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index 7d6fae77c..b0bab7d81 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -41,11 +41,11 @@ private: std::string m_message; }; -#define DEV_SIMPLE_EXCEPTION(X) struct X: virtual Exception { public: X(): Exception(#X) {} } +#define DEV_SIMPLE_EXCEPTION(X) struct X: virtual Exception { const char* what() const noexcept override { return #X; } } /// Base class for all RLP exceptions. struct RLPException: virtual Exception { RLPException(std::string _message = std::string()): Exception(_message) {} }; -#define DEV_SIMPLE_EXCEPTION_RLP(X) struct X: virtual RLPException { public: X(): RLPException(#X) {} } +#define DEV_SIMPLE_EXCEPTION_RLP(X) struct X: virtual RLPException { const char* what() const noexcept override { return #X; } } DEV_SIMPLE_EXCEPTION_RLP(BadCast); DEV_SIMPLE_EXCEPTION_RLP(BadRLP); 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; } diff --git a/libdevcore/Log.cpp b/libdevcore/Log.cpp index 1e5c2d8ab..fde492f3b 100644 --- a/libdevcore/Log.cpp +++ b/libdevcore/Log.cpp @@ -40,7 +40,7 @@ mutex x_logOverride; /// or equal to the currently output verbosity (g_logVerbosity). static map s_logOverride; -bool isLogVisible(std::type_info const* _ch, bool _default) +bool dev::isChannelVisible(std::type_info const* _ch, bool _default) { Guard l(x_logOverride); if (s_logOverride.count(_ch)) diff --git a/libdevcore/MemoryDB.cpp b/libdevcore/MemoryDB.cpp index 2cf56475b..f71931bdd 100644 --- a/libdevcore/MemoryDB.cpp +++ b/libdevcore/MemoryDB.cpp @@ -32,7 +32,9 @@ const char* DBWarn::name() { return "TDB"; } std::unordered_map MemoryDB::get() const { +#if DEV_GUARDED_DB ReadGuard l(x_this); +#endif std::unordered_map ret; for (auto const& i: m_main) if (!m_enforceRefs || i.second.second > 0) @@ -44,8 +46,10 @@ MemoryDB& MemoryDB::operator=(MemoryDB const& _c) { if (this == &_c) return *this; +#if DEV_GUARDED_DB ReadGuard l(_c.x_this); WriteGuard l2(x_this); +#endif m_main = _c.m_main; m_aux = _c.m_aux; return *this; @@ -53,7 +57,9 @@ MemoryDB& MemoryDB::operator=(MemoryDB const& _c) std::string MemoryDB::lookup(h256 const& _h) const { +#if DEV_GUARDED_DB ReadGuard l(x_this); +#endif auto it = m_main.find(_h); if (it != m_main.end()) { @@ -67,7 +73,9 @@ std::string MemoryDB::lookup(h256 const& _h) const bool MemoryDB::exists(h256 const& _h) const { +#if DEV_GUARDED_DB ReadGuard l(x_this); +#endif auto it = m_main.find(_h); if (it != m_main.end() && (!m_enforceRefs || it->second.second > 0)) return true; @@ -76,7 +84,9 @@ bool MemoryDB::exists(h256 const& _h) const void MemoryDB::insert(h256 const& _h, bytesConstRef _v) { +#if DEV_GUARDED_DB WriteGuard l(x_this); +#endif auto it = m_main.find(_h); if (it != m_main.end()) { @@ -92,7 +102,9 @@ void MemoryDB::insert(h256 const& _h, bytesConstRef _v) bool MemoryDB::kill(h256 const& _h) { +#if DEV_GUARDED_DB ReadGuard l(x_this); +#endif if (m_main.count(_h)) { if (m_main[_h].second > 0) @@ -117,9 +129,38 @@ bool MemoryDB::kill(h256 const& _h) return false; } +bytes MemoryDB::lookupAux(h256 const& _h) const +{ +#if DEV_GUARDED_DB + ReadGuard l(x_this); +#endif + auto it = m_aux.find(_h); + if (it != m_aux.end() && (!m_enforceRefs || it->second.second)) + return it->second.first; + return bytes(); +} + +void MemoryDB::removeAux(h256 const& _h) +{ +#if DEV_GUARDED_DB + WriteGuard l(x_this); +#endif + m_aux[_h].second = false; +} + +void MemoryDB::insertAux(h256 const& _h, bytesConstRef _v) +{ +#if DEV_GUARDED_DB + WriteGuard l(x_this); +#endif + m_aux[_h] = make_pair(_v.toBytes(), true); +} + void MemoryDB::purge() { +#if DEV_GUARDED_DB WriteGuard l(x_this); +#endif for (auto it = m_main.begin(); it != m_main.end(); ) if (it->second.second) ++it; @@ -129,7 +170,9 @@ void MemoryDB::purge() h256Hash MemoryDB::keys() const { +#if DEV_GUARDED_DB ReadGuard l(x_this); +#endif h256Hash ret; for (auto const& i: m_main) if (i.second.second) diff --git a/libdevcore/MemoryDB.h b/libdevcore/MemoryDB.h index 169682815..a39c0efd0 100644 --- a/libdevcore/MemoryDB.h +++ b/libdevcore/MemoryDB.h @@ -57,14 +57,16 @@ public: bool kill(h256 const& _h); void purge(); - bytes lookupAux(h256 const& _h) const { ReadGuard l(x_this); auto it = m_aux.find(_h); if (it != m_aux.end() && (!m_enforceRefs || it->second.second)) return it->second.first; return bytes(); } - void removeAux(h256 const& _h) { WriteGuard l(x_this); m_aux[_h].second = false; } - void insertAux(h256 const& _h, bytesConstRef _v) { WriteGuard l(x_this); m_aux[_h] = make_pair(_v.toBytes(), true); } + bytes lookupAux(h256 const& _h) const; + void removeAux(h256 const& _h); + void insertAux(h256 const& _h, bytesConstRef _v); h256Hash keys() const; protected: +#if DEV_GUARDED_DB mutable SharedMutex x_this; +#endif std::unordered_map> m_main; std::unordered_map> m_aux; diff --git a/libdevcore/vector_ref.h b/libdevcore/vector_ref.h index 5e9bba3e8..b04d449b3 100644 --- a/libdevcore/vector_ref.h +++ b/libdevcore/vector_ref.h @@ -43,7 +43,8 @@ public: vector_ref<_T> cropped(size_t _begin) const { if (m_data && _begin <= m_count) return vector_ref<_T>(m_data + _begin, m_count - _begin); else return vector_ref<_T>(); } void retarget(_T* _d, size_t _s) { m_data = _d; m_count = _s; } void retarget(std::vector<_T> const& _t) { m_data = _t.data(); m_count = _t.size(); } - void copyTo(vector_ref::type> _t) const { memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); } + template bool overlapsWith(vector_ref _t) const { void const* f1 = data(); void const* t1 = data() + size(); void const* f2 = _t.data(); void const* t2 = _t.data() + _t.size(); return f1 < t2 && t1 > f2; } + void copyTo(vector_ref::type> _t) const { if (overlapsWith(_t)) memmove(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); else memcpy(_t.data(), m_data, std::min(_t.size(), m_count) * sizeof(_T)); } void populate(vector_ref::type> _t) const { copyTo(_t); memset(_t.data() + m_count, 0, std::max(_t.size(), m_count) - m_count); } _T* begin() { return m_data; } diff --git a/libdevcrypto/CryptoPP.cpp b/libdevcrypto/CryptoPP.cpp index 9b550a666..40eae10f1 100644 --- a/libdevcrypto/CryptoPP.cpp +++ b/libdevcrypto/CryptoPP.cpp @@ -264,7 +264,6 @@ Public Secp256k1::recover(Signature _signature, bytesConstRef _message) ECP::Element x; { - Guard l(x_curve); m_curve.DecodePoint(x, encodedpoint, 33); if (!m_curve.VerifyPoint(x)) return recovered; @@ -286,7 +285,6 @@ Public Secp256k1::recover(Signature _signature, bytesConstRef _message) ECP::Point p; byte recoveredbytes[65]; { - Guard l(x_curve); // todo: make generator member p = m_curve.CascadeMultiply(u2, x, u1, m_params.GetSubgroupGenerator()); m_curve.EncodePoint(recoveredbytes, p, false); diff --git a/libdevcrypto/OverlayDB.cpp b/libdevcrypto/OverlayDB.cpp index 05b9877ad..a6aa684f2 100644 --- a/libdevcrypto/OverlayDB.cpp +++ b/libdevcrypto/OverlayDB.cpp @@ -50,7 +50,9 @@ void OverlayDB::commit() { ldb::WriteBatch batch; // cnote << "Committing nodes to disk DB:"; +#if DEV_GUARDED_DB DEV_READ_GUARDED(x_this) +#endif { for (auto const& i: m_main) { @@ -83,7 +85,9 @@ void OverlayDB::commit() cwarn << "Sleeping for" << (i + 1) << "seconds, then retrying."; this_thread::sleep_for(chrono::seconds(i + 1)); } +#if DEV_GUARDED_DB DEV_WRITE_GUARDED(x_this) +#endif { m_aux.clear(); m_main.clear(); @@ -107,7 +111,9 @@ bytes OverlayDB::lookupAux(h256 const& _h) const void OverlayDB::rollback() { +#if DEV_GUARDED_DB WriteGuard l(x_this); +#endif m_main.clear(); } diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 2bdcfcd9a..6c2f8269a 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 @@ -51,12 +51,14 @@ 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 add_definition(std::string& source, char const* id, unsigned value) +static void addDefinition(string& _source, char const* _id, unsigned _value) { char buf[256]; - sprintf(buf, "#define %s %uu\n", id, value); - source.insert(source.begin(), buf, buf + strlen(buf)); + sprintf(buf, "#define %s %uu\n", _id, _value); + _source.insert(_source.begin(), buf, buf + strlen(buf)); } ethash_cl_miner::search_hook::~search_hook() {} @@ -71,44 +73,54 @@ ethash_cl_miner::~ethash_cl_miner() finish(); } -std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _deviceId) +string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _deviceId) { - std::vector platforms; + vector platforms; cl::Platform::get(&platforms); if (platforms.empty()) { ETHCL_LOG("No OpenCL platforms found."); - return std::string(); + return string(); } // get GPU device of the selected platform - std::vector devices; - unsigned platform_num = std::min(_platformId, platforms.size() - 1); - platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); + unsigned platform_num = min(_platformId, platforms.size() - 1); + vector devices = getDevices(platforms, _platformId); if (devices.empty()) { ETHCL_LOG("No OpenCL devices found."); - return std::string(); + return string(); } // use selected default device - unsigned device_num = std::min(_deviceId, devices.size() - 1); + unsigned device_num = min(_deviceId, devices.size() - 1); cl::Device& device = devices[device_num]; - std::string device_version = device.getInfo(); + string device_version = device.getInfo(); return "{ \"platform\": \"" + platforms[platform_num].getInfo() + "\", \"device\": \"" + device.getInfo() + "\", \"version\": \"" + device_version + "\" }"; } -unsigned ethash_cl_miner::get_num_platforms() +std::vector ethash_cl_miner::getDevices(std::vector const& _platforms, unsigned _platformId) { - std::vector platforms; + 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; cl::Platform::get(&platforms); return platforms.size(); } -unsigned ethash_cl_miner::get_num_devices(unsigned _platformId) +unsigned ethash_cl_miner::getNumDevices(unsigned _platformId) { - std::vector platforms; + vector platforms; cl::Platform::get(&platforms); if (platforms.empty()) { @@ -116,9 +128,7 @@ unsigned ethash_cl_miner::get_num_devices(unsigned _platformId) return 0; } - std::vector devices; - unsigned platform_num = std::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."); @@ -127,9 +137,49 @@ unsigned ethash_cl_miner::get_num_devices(unsigned _platformId) return devices.size(); } -bool ethash_cl_miner::haveSufficientGPUMemory() +bool ethash_cl_miner::configureGPU( + bool _allowCPU, + unsigned _extraGPUMemory, + bool _forceSingleChunk, + boost::optional _currentBlock +) { - std::vector platforms; + 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; + 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 >= requiredSize) + { + ETHCL_LOG( + "Found suitable OpenCL device [" << _device.getInfo() + << "] with " << result << " bytes of GPU memory" + ); + return true; + } + + ETHCL_LOG( + "OpenCL device " << _device.getInfo() + << " has insufficient GPU memory." << result << + " bytes of memory found < " << requiredSize << " bytes of memory required" + ); + return false; + } + ); +} + +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) +{ + vector platforms; cl::Platform::get(&platforms); if (platforms.empty()) { @@ -137,50 +187,30 @@ bool ethash_cl_miner::haveSufficientGPUMemory() return false; } for (unsigned i = 0; i < platforms.size(); ++i) - if (haveSufficientGPUMemory(i)) + if (searchForAllDevices(i, _callback)) return true; return false; } -bool ethash_cl_miner::haveSufficientGPUMemory(unsigned _platformId) +bool ethash_cl_miner::searchForAllDevices(unsigned _platformId, function _callback) { - std::vector platforms; + vector platforms; cl::Platform::get(&platforms); if (_platformId >= platforms.size()) return false; - std::vector devices; - unsigned platform_num = std::min(_platformId, platforms.size() - 1); - platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); - if (devices.empty()) - return false; - + vector devices = getDevices(platforms, _platformId); for (cl::Device const& device: devices) - { - cl_ulong result; - device.getInfo(CL_DEVICE_GLOBAL_MEM_SIZE, &result); - if (result >= ETHASH_CL_MINIMUM_MEMORY) - { - ETHCL_LOG( - "Found suitable OpenCL device [" << device.getInfo() - << "] with " << result << " bytes of GPU memory" - ); + if (_callback(device)) return true; - } - else - ETHCL_LOG( - "OpenCL device " << device.getInfo() - << " has insufficient GPU memory." << result << - " bytes of memory found < " << ETHASH_CL_MINIMUM_MEMORY << " bytes of memory required" - ); - } + return false; } -void ethash_cl_miner::listDevices() +void ethash_cl_miner::doForAllDevices(function _callback) { - std::vector platforms; + vector platforms; cl::Platform::get(&platforms); if (platforms.empty()) { @@ -188,26 +218,31 @@ void ethash_cl_miner::listDevices() return; } for (unsigned i = 0; i < platforms.size(); ++i) - listDevices(i); + doForAllDevices(i, _callback); } -void ethash_cl_miner::listDevices(unsigned _platformId) +void ethash_cl_miner::doForAllDevices(unsigned _platformId, function _callback) { - std::vector platforms; + vector platforms; cl::Platform::get(&platforms); if (_platformId >= platforms.size()) return; - std::string outString ="Listing OpenCL devices for platform " + to_string(_platformId) + "\n[deviceID] deviceName\n"; - std::vector devices; - platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices); - unsigned i = 0; - std::string deviceString; + vector devices = getDevices(platforms, _platformId); for (cl::Device const& device: devices) - { - outString += "[" + to_string(i) + "] " + device.getInfo() + "\n"; - ++i; - } + _callback(device); +} + +void ethash_cl_miner::listDevices() +{ + string outString ="\nListing OpenCL devices.\nFORMAT: [deviceID] deviceName\n"; + unsigned int i = 0; + doForAllDevices([&outString, &i](cl::Device const _device) + { + outString += "[" + to_string(i) + "] " + _device.getInfo() + "\n"; + ++i; + } + ); ETHCL_LOG(outString); } @@ -222,19 +257,13 @@ bool ethash_cl_miner::init( uint64_t _dagSize, unsigned workgroup_size, unsigned _platformId, - unsigned _deviceId, - unsigned _dagChunksNum + unsigned _deviceId ) { - // for now due to the .cl kernels we can only have either 1 big chunk or 4 chunks - assert(_dagChunksNum == 1 || _dagChunksNum == 4); - // now create the number of chunk buffers - m_dagChunksNum = _dagChunksNum; - // get all platforms try { - std::vector platforms; + vector platforms; cl::Platform::get(&platforms); if (platforms.empty()) { @@ -243,12 +272,11 @@ bool ethash_cl_miner::init( } // use selected platform - _platformId = std::min(_platformId, platforms.size() - 1); + _platformId = min(_platformId, platforms.size() - 1); ETHCL_LOG("Using platform: " << platforms[_platformId].getInfo().c_str()); // get GPU device of the default platform - std::vector devices; - platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices); + vector devices = getDevices(platforms, _platformId); if (devices.empty()) { ETHCL_LOG("No OpenCL devices found."); @@ -256,10 +284,27 @@ bool ethash_cl_miner::init( } // use selected device - cl::Device& device = devices[std::min(_deviceId, devices.size() - 1)]; - std::string device_version = device.getInfo(); + cl::Device& device = devices[min(_deviceId, devices.size() - 1)]; + string device_version = device.getInfo(); ETHCL_LOG("Using device: " << device.getInfo().c_str() << "(" << device_version.c_str() << ")"); + // configure chunk number depending on max allocateable memory + cl_ulong result; + device.getInfo(CL_DEVICE_MAX_MEM_ALLOC_SIZE, &result); + if (s_forceSingleChunk || result >= _dagSize) + { + m_dagChunksNum = 1; + 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); + } + if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0) { ETHCL_LOG("OpenCL 1.0 is not supported."); @@ -269,7 +314,7 @@ bool ethash_cl_miner::init( m_opencl_1_1 = true; // create context - m_context = cl::Context(std::vector(&device, &device + 1)); + m_context = cl::Context(vector(&device, &device + 1)); m_queue = cl::CommandQueue(m_context, device); // use requested workgroup size, but we require multiple of 8 @@ -278,11 +323,11 @@ bool ethash_cl_miner::init( // patch source code // note: ETHASH_CL_MINER_KERNEL is simply ethash_cl_miner_kernel.cl compiled // into a byte array by bin2h.cmake. There is no need to load the file by hand in runtime - std::string code(ETHASH_CL_MINER_KERNEL, ETHASH_CL_MINER_KERNEL + ETHASH_CL_MINER_KERNEL_SIZE); - add_definition(code, "GROUP_SIZE", m_workgroup_size); - add_definition(code, "DAG_SIZE", (unsigned)(_dagSize / ETHASH_MIX_BYTES)); - add_definition(code, "ACCESSES", ETHASH_ACCESSES); - add_definition(code, "MAX_OUTPUTS", c_max_search_results); + string code(ETHASH_CL_MINER_KERNEL, ETHASH_CL_MINER_KERNEL + ETHASH_CL_MINER_KERNEL_SIZE); + addDefinition(code, "GROUP_SIZE", m_workgroup_size); + addDefinition(code, "DAG_SIZE", (unsigned)(_dagSize / ETHASH_MIX_BYTES)); + addDefinition(code, "ACCESSES", ETHASH_ACCESSES); + addDefinition(code, "MAX_OUTPUTS", c_max_search_results); //debugf("%s", code.c_str()); // create miner OpenCL program @@ -301,7 +346,7 @@ bool ethash_cl_miner::init( ETHCL_LOG(program.getBuildInfo(device).c_str()); return false; } - if (_dagChunksNum == 1) + if (m_dagChunksNum == 1) { ETHCL_LOG("Loading single big chunk kernels"); m_hash_kernel = cl::Kernel(program, "ethash_hash"); @@ -315,13 +360,13 @@ bool ethash_cl_miner::init( } // create buffer for dag - if (_dagChunksNum == 1) + if (m_dagChunksNum == 1) { ETHCL_LOG("Creating one big buffer"); m_dagChunks.push_back(cl::Buffer(m_context, CL_MEM_READ_ONLY, _dagSize)); } else - for (unsigned i = 0; i < _dagChunksNum; i++) + for (unsigned i = 0; i < m_dagChunksNum; i++) { // TODO Note: If we ever change to _dagChunksNum other than 4, then the size would need recalculation ETHCL_LOG("Creating buffer for chunk " << i); @@ -336,7 +381,7 @@ bool ethash_cl_miner::init( ETHCL_LOG("Creating buffer for header."); m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32); - if (_dagChunksNum == 1) + if (m_dagChunksNum == 1) { ETHCL_LOG("Mapping one big chunk."); m_queue.enqueueWriteBuffer(m_dagChunks[0], CL_TRUE, 0, _dagSize, _dag); @@ -345,12 +390,12 @@ bool ethash_cl_miner::init( { // TODO Note: If we ever change to _dagChunksNum other than 4, then the size would need recalculation void* dag_ptr[4]; - for (unsigned i = 0; i < _dagChunksNum; i++) + for (unsigned i = 0; i < m_dagChunksNum; i++) { ETHCL_LOG("Mapping chunk " << i); dag_ptr[i] = m_queue.enqueueMapBuffer(m_dagChunks[i], true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7); } - for (unsigned i = 0; i < _dagChunksNum; i++) + for (unsigned i = 0; i < m_dagChunksNum; i++) { memcpy(dag_ptr[i], (char *)_dag + i*((_dagSize >> 9) << 7), (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7); m_queue.enqueueUnmapMemObject(m_dagChunks[i], dag_ptr[i]); @@ -382,7 +427,7 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook uint64_t start_nonce; unsigned buf; }; - std::queue pending; + queue pending; static uint32_t const c_zero = 0; @@ -408,8 +453,8 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook m_search_kernel.setArg(argPos + 2, ~0u); unsigned buf = 0; - std::random_device engine; - uint64_t start_nonce = std::uniform_int_distribution()(engine); + random_device engine; + uint64_t start_nonce = uniform_int_distribution()(engine); for (;; start_nonce += c_search_batch_size) { // supply output buffer to kernel @@ -432,7 +477,7 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook // could use pinned host pointer instead uint32_t* results = (uint32_t*)m_queue.enqueueMapBuffer(m_search_buf[batch.buf], true, CL_MAP_READ, 0, (1 + c_max_search_results) * sizeof(uint32_t)); - unsigned num_found = std::min(results[0], c_max_search_results); + unsigned num_found = min(results[0], c_max_search_results); uint64_t nonces[c_max_search_results]; for (unsigned i = 0; i != num_found; ++i) diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index 4d5317186..cc01b0057 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 @@ -32,21 +33,27 @@ public: ethash_cl_miner(); ~ethash_cl_miner(); - static unsigned get_num_platforms(); - static unsigned get_num_devices(unsigned _platformId = 0); + static bool searchForAllDevices(unsigned _platformId, std::function _callback); + static bool searchForAllDevices(std::function _callback); + static void doForAllDevices(unsigned _platformId, std::function _callback); + static void doForAllDevices(std::function _callback); + static unsigned getNumPlatforms(); + static unsigned getNumDevices(unsigned _platformId = 0); static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0); - static bool haveSufficientGPUMemory(); - static bool haveSufficientGPUMemory(unsigned _platformId); static void listDevices(); - static void listDevices(unsigned _platformId); + static bool configureGPU( + bool _allowCPU, + unsigned _extraGPUMemory, + bool _forceSingleChunk, + boost::optional _currentBlock + ); bool init( uint8_t const* _dag, uint64_t _dagSize, unsigned workgroup_size = 64, unsigned _platformId = 0, - unsigned _deviceId = 0, - unsigned _dagChunksNum = 1 + unsigned _deviceId = 0 ); void finish(); void search(uint8_t const* header, uint64_t target, search_hook& hook); @@ -55,17 +62,28 @@ 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; cl::CommandQueue m_queue; cl::Kernel m_hash_kernel; cl::Kernel m_search_kernel; - unsigned m_dagChunksNum; + unsigned int m_dagChunksNum; std::vector m_dagChunks; cl::Buffer m_header; cl::Buffer m_hash_buf[c_num_buffers]; cl::Buffer m_search_buf[c_num_buffers]; 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. + /// User can set it via the --cl-extragpu-mem argument. + static unsigned s_extraRequiredGPUMem; }; diff --git a/libethash-cl/ethash_cl_miner_kernel.cl b/libethash-cl/ethash_cl_miner_kernel.cl index 8567bb164..2143435ed 100644 --- a/libethash-cl/ethash_cl_miner_kernel.cl +++ b/libethash-cl/ethash_cl_miner_kernel.cl @@ -585,4 +585,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/Common.cpp b/libethcore/Common.cpp index 63f4a19f9..618703e22 100644 --- a/libethcore/Common.cpp +++ b/libethcore/Common.cpp @@ -112,25 +112,26 @@ std::string formatBalance(bigint const& _b) static void badBlockInfo(BlockInfo const& _bi, string const& _err) { - cwarn << EthRedBold << "========================================================================"; - cwarn << EthRedBold << "== Software Failure " + _err + string(max(0, 44 - _err.size()), ' ') + " =="; + string const c_line = EthReset EthOnMaroon + string(80, ' '); + string const c_border = EthReset EthOnMaroon + string(2, ' ') + EthReset EthMaroonBold; + string const c_space = c_border + string(76, ' ') + c_border; + stringstream ss; + ss << c_line << endl; + ss << c_space << endl; + ss << c_border + " Import Failure " + _err + string(max(0, 53 - _err.size()), ' ') + " " + c_border << endl; + ss << c_space << endl; string bin = toString(_bi.number); - cwarn << EthRedBold << ("== Guru Meditation #" + string(max(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " =="); - cwarn << EthRedBold << "========================================================================"; + ss << c_border + (" Guru Meditation #" + string(max(0, 8 - bin.size()), '0') + bin + "." + _bi.hash().abridged() + " ") + c_border << endl; + ss << c_space << endl; + ss << c_line; + cwarn << "\n" + ss.str(); } void badBlock(bytesConstRef _block, string const& _err) { - badBlockInfo(BlockInfo(_block, CheckNothing), _err); - cwarn << " Block:" << toHex(_block); - cwarn << " Block RLP:" << RLP(_block); -} - -void badBlockHeader(bytesConstRef _header, string const& _err) -{ - badBlockInfo(BlockInfo::fromHeader(_header, CheckNothing), _err); - cwarn << " Header:" << toHex(_header); - cwarn << " Header RLP:" << RLP(_header);; + BlockInfo bi; + DEV_IGNORE_EXCEPTIONS(bi = BlockInfo(_block, CheckNothing)); + badBlockInfo(bi, _err); } } diff --git a/libethcore/Common.h b/libethcore/Common.h index 87ebffab7..6f23cb0e8 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -85,6 +85,10 @@ using BlockNumber = unsigned; static const BlockNumber LatestBlock = (BlockNumber)-2; static const BlockNumber PendingBlock = (BlockNumber)-1; +static const h256 LatestBlockHash = h256(2); +static const h256 EarliestBlockHash = h256(1); +static const h256 PendingBlockHash = h256(0); + enum class RelativeBlock: BlockNumber { @@ -119,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; @@ -156,8 +175,6 @@ struct TransactionSkeleton u256 gasPrice = UndefinedU256; }; -void badBlockHeader(bytesConstRef _header, std::string const& _err); -inline void badBlockHeader(bytes const& _header, std::string const& _err) { badBlockHeader(&_header, _err); } void badBlock(bytesConstRef _header, std::string const& _err); inline void badBlock(bytes const& _header, std::string const& _err) { badBlock(&_header, _err); } diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index f715d6912..2c743f33b 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -285,7 +285,6 @@ private: unsigned Ethash::GPUMiner::s_platformId = 0; unsigned Ethash::GPUMiner::s_deviceId = 0; unsigned Ethash::GPUMiner::s_numInstances = 0; -unsigned Ethash::GPUMiner::s_dagChunks = 1; Ethash::GPUMiner::GPUMiner(ConstructionInfo const& _ci): Miner(_ci), @@ -335,18 +334,19 @@ void Ethash::GPUMiner::workLoop() EthashAux::FullType dag; while (true) { - if ((dag = EthashAux::full(w.seedHash, false))) + if ((dag = EthashAux::full(w.seedHash, true))) break; if (shouldStop()) { delete m_miner; + m_miner = nullptr; return; } cnote << "Awaiting DAG"; this_thread::sleep_for(chrono::milliseconds(500)); } bytesConstRef dagData = dag->data(); - m_miner->init(dagData.data(), dagData.size(), 32, s_platformId, device, s_dagChunks); + m_miner->init(dagData.data(), dagData.size(), 32, s_platformId, device); } uint64_t upper64OfBoundary = (uint64_t)(u64)((u256)w.boundary >> 192); @@ -354,6 +354,8 @@ void Ethash::GPUMiner::workLoop() } catch (cl::Error const& _e) { + delete m_miner; + m_miner = nullptr; cwarn << "Error GPU mining: " << _e.what() << "(" << _e.err() << ")"; } } @@ -371,7 +373,7 @@ std::string Ethash::GPUMiner::platformInfo() unsigned Ethash::GPUMiner::getNumDevices() { - return ethash_cl_miner::get_num_devices(s_platformId); + return ethash_cl_miner::getNumDevices(s_platformId); } void Ethash::GPUMiner::listDevices() @@ -379,9 +381,18 @@ void Ethash::GPUMiner::listDevices() return ethash_cl_miner::listDevices(); } -bool Ethash::GPUMiner::haveSufficientMemory() +bool Ethash::GPUMiner::configureGPU( + unsigned _platformId, + unsigned _deviceId, + bool _allowCPU, + unsigned _extraGPUMemory, + bool _forceSingleChunk, + boost::optional _currentBlock +) { - return ethash_cl_miner::haveSufficientGPUMemory(); + s_platformId = _platformId; + s_deviceId = _deviceId; + return ethash_cl_miner::configureGPU(_allowCPU, _extraGPUMemory, _forceSingleChunk, _currentBlock); } #endif diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 99df1dc71..a5a7856f1 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -87,11 +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 haveSufficientMemory() { 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 @@ -120,11 +117,15 @@ public: static std::string platformInfo(); static unsigned getNumDevices(); static void listDevices(); - static bool haveSufficientMemory(); - 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, + unsigned _extraGPUMemory, + bool _forceSingleChunk, + boost::optional _currentBlock + ); static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, getNumDevices()); } - static void setDagChunks(unsigned _dagChunks) { s_dagChunks = _dagChunks; } protected: void kickOff() override; @@ -143,7 +144,6 @@ public: static unsigned s_platformId; static unsigned s_deviceId; static unsigned s_numInstances; - static unsigned s_dagChunks; }; #else using GPUMiner = CPUMiner; 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); diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index 3838dd362..bd6996a45 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -42,13 +43,14 @@ #include "GenesisInfo.h" #include "State.h" #include "Defaults.h" + using namespace std; using namespace dev; using namespace dev::eth; namespace js = json_spirit; #define ETH_CATCH 1 -#define ETH_TIMED_IMPORTS 0 +#define ETH_TIMED_IMPORTS 1 #ifdef _WIN32 const char* BlockChainDebug::name() { return EthBlue "8" EthWhite " <>"; } @@ -307,47 +309,50 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _st { // _bq.tick(*this); - vector> blocks; + VerifiedBlocks blocks; _bq.drain(blocks, _max); h256s fresh; h256s dead; h256s badBlocks; - for (auto const& block: blocks) - { - try - { - // Nonce & uncle nonces already verified in verification thread at this point. - ImportRoute r; - DEV_TIMED_ABOVE(Block import, 500) - r = import(block.first, block.second, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); - fresh += r.first; - dead += r.second; - } - catch (dev::eth::UnknownParent) - { - cwarn << "ODD: Import queue contains block with unknown parent." << LogTag::Error << boost::current_exception_diagnostic_information(); - // NOTE: don't reimport since the queue should guarantee everything in the right order. - // Can't continue - chain bad. - badBlocks.push_back(block.first.hash()); - } - catch (dev::eth::FutureTime) - { - cwarn << "ODD: Import queue contains a block with future time." << LogTag::Error << boost::current_exception_diagnostic_information(); - // NOTE: don't reimport since the queue should guarantee everything in the past. - // Can't continue - chain bad. - badBlocks.push_back(block.first.hash()); - } - catch (Exception& ex) + for (VerifiedBlock const& block: blocks) + if (!badBlocks.empty()) + badBlocks.push_back(block.verified.info.hash()); + else { - cnote << "Exception while importing block. Someone (Jeff? That you?) seems to be giving us dodgy blocks!" << LogTag::Error << diagnostic_information(ex); - if (m_onBad) - m_onBad(ex); - // NOTE: don't reimport since the queue should guarantee everything in the right order. - // Can't continue - chain bad. - badBlocks.push_back(block.first.hash()); + try + { + // Nonce & uncle nonces already verified in verification thread at this point. + ImportRoute r; + DEV_TIMED_ABOVE(Block import, 500) + r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); + fresh += r.first; + dead += r.second; + } + catch (dev::eth::UnknownParent) + { + cwarn << "ODD: Import queue contains block with unknown parent.";// << LogTag::Error << boost::current_exception_diagnostic_information(); + // NOTE: don't reimport since the queue should guarantee everything in the right order. + // Can't continue - chain bad. + badBlocks.push_back(block.verified.info.hash()); + } + catch (dev::eth::FutureTime) + { + cwarn << "ODD: Import queue contains a block with future time.";// << LogTag::Error << boost::current_exception_diagnostic_information(); + // NOTE: don't reimport since the queue should guarantee everything in the past. + // Can't continue - chain bad. + badBlocks.push_back(block.verified.info.hash()); + } + catch (Exception& ex) + { +// cnote << "Exception while importing block. Someone (Jeff? That you?) seems to be giving us dodgy blocks!";// << LogTag::Error << diagnostic_information(ex); + if (m_onBad) + m_onBad(ex); + // NOTE: don't reimport since the queue should guarantee everything in the right order. + // Can't continue - chain bad. + badBlocks.push_back(block.verified.info.hash()); + } } - } return make_tuple(fresh, dead, _bq.doneDrain(badBlocks)); } @@ -355,7 +360,7 @@ pair BlockChain::attemptImport(bytes const& _block, O { try { - return make_pair(ImportResult::Success, import(_block, _stateDB, _ir)); + return make_pair(ImportResult::Success, import(verifyBlock(_block, m_onBad, _ir), _stateDB, _ir)); } catch (UnknownParent&) { @@ -380,29 +385,28 @@ pair BlockChain::attemptImport(bytes const& _block, O ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, ImportRequirements::value _ir) { // VERIFY: populates from the block and checks the block is internally coherent. - BlockInfo bi; + VerifiedBlockRef block; #if ETH_CATCH try #endif { - bi.populate(&_block); - bi.verifyInternals(&_block); + block = verifyBlock(_block, m_onBad); } #if ETH_CATCH catch (Exception& ex) { - clog(BlockChainNote) << " Malformed block: " << diagnostic_information(ex); +// clog(BlockChainNote) << " Malformed block: " << diagnostic_information(ex); ex << errinfo_now(time(0)); ex << errinfo_block(_block); throw; } #endif - return import(bi, _block, _db, _ir); + return import(block, _db, _ir); } -ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, OverlayDB const& _db, ImportRequirements::value _ir) +ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir) { //@tidy This is a behemoth of a method - could do to be split into a few smaller ones. @@ -417,28 +421,28 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla #endif // Check block doesn't already exist first! - if (isKnown(_bi.hash()) && (_ir & ImportRequirements::DontHave)) + if (isKnown(_block.info.hash()) && (_ir & ImportRequirements::DontHave)) { - clog(BlockChainNote) << _bi.hash() << ": Not new."; + clog(BlockChainNote) << _block.info.hash() << ": Not new."; BOOST_THROW_EXCEPTION(AlreadyHaveBlock()); } // Work out its number as the parent's number + 1 - if (!isKnown(_bi.parentHash)) + if (!isKnown(_block.info.parentHash)) { - clog(BlockChainNote) << _bi.hash() << ": Unknown parent " << _bi.parentHash; + clog(BlockChainNote) << _block.info.hash() << ": Unknown parent " << _block.info.parentHash; // We don't know the parent (yet) - discard for now. It'll get resent to us if we find out about its ancestry later on. BOOST_THROW_EXCEPTION(UnknownParent()); } - auto pd = details(_bi.parentHash); + auto pd = details(_block.info.parentHash); if (!pd) { auto pdata = pd.rlp(); clog(BlockChainDebug) << "Details is returning false despite block known:" << RLP(pdata); - auto parentBlock = block(_bi.parentHash); - clog(BlockChainDebug) << "isKnown:" << isKnown(_bi.parentHash); - clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _bi.number; + auto parentBlock = block(_block.info.parentHash); + clog(BlockChainDebug) << "isKnown:" << isKnown(_block.info.parentHash); + clog(BlockChainDebug) << "last/number:" << m_lastBlockNumber << m_lastBlockHash << _block.info.number; clog(BlockChainDebug) << "Block:" << BlockInfo(parentBlock); clog(BlockChainDebug) << "RLP:" << RLP(parentBlock); clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; @@ -446,14 +450,14 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla } // Check it's not crazy - if (_bi.timestamp > (u256)time(0)) + if (_block.info.timestamp > (u256)time(0)) { - clog(BlockChainChat) << _bi.hash() << ": Future time " << _bi.timestamp << " (now at " << time(0) << ")"; + clog(BlockChainChat) << _block.info.hash() << ": Future time " << _block.info.timestamp << " (now at " << time(0) << ")"; // Block has a timestamp in the future. This is no good. BOOST_THROW_EXCEPTION(FutureTime()); } - clog(BlockChainChat) << "Attempting import of " << _bi.hash() << "..."; + clog(BlockChainChat) << "Attempting import of " << _block.info.hash() << "..."; #if ETH_TIMED_IMPORTS preliminaryChecks = t.elapsed(); @@ -473,7 +477,7 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla // Check transactions are valid and that they result in a state equivalent to our state_root. // Get total difficulty increase and update state, checking it. State s(_db); - auto tdIncrease = s.enactOn(&_block, _bi, *this, _ir); + auto tdIncrease = s.enactOn(_block, *this, _ir); BlockLogBlooms blb; BlockReceipts br; @@ -503,22 +507,22 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla // together with an "ensureCachedWithUpdatableLock(l)" method. // This is safe in practice since the caches don't get flushed nearly often enough to be // done here. - details(_bi.parentHash); + details(_block.info.parentHash); DEV_WRITE_GUARDED(x_details) - m_details[_bi.parentHash].children.push_back(_bi.hash()); + m_details[_block.info.parentHash].children.push_back(_block.info.hash()); #if ETH_TIMED_IMPORTS || !ETH_TRUE collation = t.elapsed(); t.restart(); #endif - blocksBatch.Put(toSlice(_bi.hash()), (ldb::Slice)ref(_block)); + blocksBatch.Put(toSlice(_block.info.hash()), ldb::Slice(_block.block)); DEV_READ_GUARDED(x_details) - extrasBatch.Put(toSlice(_bi.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[_bi.parentHash].rlp())); + extrasBatch.Put(toSlice(_block.info.parentHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[_block.info.parentHash].rlp())); - extrasBatch.Put(toSlice(_bi.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _bi.parentHash, {}).rlp())); - extrasBatch.Put(toSlice(_bi.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp())); - extrasBatch.Put(toSlice(_bi.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.rlp())); + extrasBatch.Put(toSlice(_block.info.hash(), ExtraDetails), (ldb::Slice)dev::ref(BlockDetails((unsigned)pd.number + 1, td, _block.info.parentHash, {}).rlp())); + extrasBatch.Put(toSlice(_block.info.hash(), ExtraLogBlooms), (ldb::Slice)dev::ref(blb.rlp())); + extrasBatch.Put(toSlice(_block.info.hash(), ExtraReceipts), (ldb::Slice)dev::ref(br.rlp())); #if ETH_TIMED_IMPORTS || !ETH_TRUE writing = t.elapsed(); @@ -533,23 +537,18 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla } catch (Exception& ex) { - clog(BlockChainWarn) << " Malformed block: " << diagnostic_information(ex); - clog(BlockChainWarn) << "Block: " << _bi.hash(); - clog(BlockChainWarn) << _bi; - clog(BlockChainWarn) << "Block parent: " << _bi.parentHash; - clog(BlockChainWarn) << BlockInfo(block(_bi.parentHash)); ex << errinfo_now(time(0)); - ex << errinfo_block(_block); + ex << errinfo_block(_block.block.toBytes()); throw; } #endif StructuredLogger::chainReceivedNewBlock( - _bi.headerHash(WithoutNonce).abridged(), - _bi.nonce.abridged(), + _block.info.headerHash(WithoutNonce).abridged(), + _block.info.nonce.abridged(), currentHash().abridged(), "", // TODO: remote id ?? - _bi.parentHash.abridged() + _block.info.parentHash.abridged() ); // cnote << "Parent " << bi.parentHash << " has " << details(bi.parentHash).children.size() << " children."; @@ -562,8 +561,8 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla // don't include bi.hash() in treeRoute, since it's not yet in details DB... // just tack it on afterwards. unsigned commonIndex; - tie(route, common, commonIndex) = treeRoute(last, _bi.parentHash); - route.push_back(_bi.hash()); + tie(route, common, commonIndex) = treeRoute(last, _block.info.parentHash); + route.push_back(_block.info.hash()); // Most of the time these two will be equal - only when we're doing a chain revert will they not be if (common != last) @@ -575,8 +574,8 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla for (auto i = route.rbegin(); i != route.rend() && *i != common; ++i) { BlockInfo tbi; - if (*i == _bi.hash()) - tbi = _bi; + if (*i == _block.info.hash()) + tbi = _block.info; else tbi = BlockInfo(block(*i)); @@ -603,7 +602,7 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla h256s newTransactionAddresses; { bytes blockBytes; - RLP blockRLP(*i == _bi.hash() ? _block : (blockBytes = block(*i))); + RLP blockRLP(*i == _block.info.hash() ? _block.block : &(blockBytes = block(*i))); TransactionAddress ta; ta.blockHash = tbi.hash(); for (ta.index = 0; ta.index < blockRLP[1].itemCount(); ++ta.index) @@ -619,17 +618,17 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla // FINALLY! change our best hash. { - newLastBlockHash = _bi.hash(); - newLastBlockNumber = (unsigned)_bi.number; + newLastBlockHash = _block.info.hash(); + newLastBlockNumber = (unsigned)_block.info.number; } - clog(BlockChainNote) << " Imported and best" << td << " (#" << _bi.number << "). Has" << (details(_bi.parentHash).children.size() - 1) << "siblings. Route:" << route; + clog(BlockChainNote) << " Imported and best" << td << " (#" << _block.info.number << "). Has" << (details(_block.info.parentHash).children.size() - 1) << "siblings. Route:" << route; StructuredLogger::chainNewHead( - _bi.headerHash(WithoutNonce).abridged(), - _bi.nonce.abridged(), + _block.info.headerHash(WithoutNonce).abridged(), + _block.info.nonce.abridged(), currentHash().abridged(), - _bi.parentHash.abridged() + _block.info.parentHash.abridged() ); } else @@ -640,24 +639,26 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla m_blocksDB->Write(m_writeOptions, &blocksBatch); m_extrasDB->Write(m_writeOptions, &extrasBatch); - if (isKnown(_bi.hash()) && !details(_bi.hash())) +#if ETH_PARANOIA || !ETH_TRUE + if (isKnown(_block.info.hash()) && !details(_block.info.hash())) { clog(BlockChainDebug) << "Known block just inserted has no details."; - clog(BlockChainDebug) << "Block:" << _bi; + clog(BlockChainDebug) << "Block:" << _block.info; clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; exit(-1); } try { - State canary(_db, *this, _bi.hash(), ImportRequirements::DontHave); + State canary(_db, *this, _block.info.hash(), ImportRequirements::DontHave); } catch (...) { clog(BlockChainDebug) << "Failed to initialise State object form imported block."; - clog(BlockChainDebug) << "Block:" << _bi; + clog(BlockChainDebug) << "Block:" << _block.info; clog(BlockChainDebug) << "DATABASE CORRUPTION: CRITICAL FAILURE"; exit(-1); } +#endif if (m_lastBlockHash != newLastBlockHash) DEV_WRITE_GUARDED(x_lastBlockHash) @@ -673,12 +674,16 @@ ImportRoute BlockChain::import(BlockInfo const& _bi, bytes const& _block, Overla #if ETH_TIMED_IMPORTS checkBest = t.elapsed(); - cnote << "Import took:" << total.elapsed(); - cnote << "preliminaryChecks:" << preliminaryChecks; - cnote << "enactment:" << enactment; - cnote << "collation:" << collation; - cnote << "writing:" << writing; - cnote << "checkBest:" << checkBest; + if (total.elapsed() > 1.0) + { + cnote << "SLOW IMPORT:" << _block.info.hash(); + cnote << " Import took:" << total.elapsed(); + cnote << " preliminaryChecks:" << preliminaryChecks; + cnote << " enactment:" << enactment; + cnote << " collation:" << collation; + cnote << " writing:" << writing; + cnote << " checkBest:" << checkBest; + } #endif if (!route.empty()) @@ -921,8 +926,8 @@ void BlockChain::checkConsistency() delete it; } -static inline unsigned upow(unsigned a, unsigned b) { while (b-- > 0) a *= a; return a; } -static inline unsigned ceilDiv(unsigned n, unsigned d) { return n / (n + d - 1); } +static inline unsigned upow(unsigned a, unsigned b) { if (!b) return 1; while (--b > 0) a *= a; return a; } +static inline unsigned ceilDiv(unsigned n, unsigned d) { return (n + d - 1) / d; } //static inline unsigned floorDivPow(unsigned n, unsigned a, unsigned b) { return n / upow(a, b); } //static inline unsigned ceilDivPow(unsigned n, unsigned a, unsigned b) { return ceilDiv(n, upow(a, b)); } @@ -1060,3 +1065,63 @@ bytes BlockChain::block(h256 const& _hash) const return m_blocks[_hash]; } + +VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function const& _onBad, ImportRequirements::value _ir) +{ + VerifiedBlockRef res; + try + { + Strictness strictness = Strictness::CheckEverything; + if (_ir & ~ImportRequirements::ValidNonce) + strictness = Strictness::IgnoreNonce; + + res.info.populate(_block, strictness); + res.info.verifyInternals(&_block); + } + catch (Exception& ex) + { + ex << errinfo_now(time(0)); + ex << errinfo_block(_block); + if (_onBad) + _onBad(ex); + throw; + } + + RLP r(_block); + unsigned i = 0; + for (auto const& uncle: r[2]) + { + try + { + BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything); + } + catch (Exception& ex) + { + ex << errinfo_uncleIndex(i); + ex << errinfo_now(time(0)); + ex << errinfo_block(_block); + if (_onBad) + _onBad(ex); + throw; + } + ++i; + } + i = 0; + for (auto const& tr: r[1]) + { + try + { + res.transactions.push_back(Transaction(tr.data(), CheckTransaction::Everything)); + } + catch (Exception& ex) + { + ex << errinfo_transactionIndex(i); + ex << errinfo_block(_block); + throw; + } + ++i; + } + res.block = bytesConstRef(&_block); + return move(res); +} + diff --git a/libethereum/BlockChain.h b/libethereum/BlockChain.h index 06a22e27b..534173a9a 100644 --- a/libethereum/BlockChain.h +++ b/libethereum/BlockChain.h @@ -40,6 +40,7 @@ #include "Account.h" #include "Transaction.h" #include "BlockQueue.h" +#include "VerifiedBlock.h" namespace ldb = leveldb; namespace std @@ -120,7 +121,7 @@ public: /// Import block into disk-backed DB /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. ImportRoute import(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default); - ImportRoute import(BlockInfo const& _bi, bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir = ImportRequirements::Default); + ImportRoute import(VerifiedBlockRef const& _block, OverlayDB const& _db, ImportRequirements::value _ir = ImportRequirements::Default); /// Returns true if the given block is known (though not necessarily a part of the canon chain). bool isKnown(h256 const& _hash) const; @@ -143,6 +144,7 @@ public: BlockLogBlooms logBlooms() const { return logBlooms(currentHash()); } /// Get the transactions' receipts of a block (or the most recent mined if none given). Thread-safe. + /// receipts are given in the same order are in the same order as the transactions BlockReceipts receipts(h256 const& _hash) const { return queryExtras(_hash, m_receipts, x_receipts, NullBlockReceipts); } BlockReceipts receipts() const { return receipts(currentHash()); } @@ -256,6 +258,9 @@ public: /// Deallocate unused data. void garbageCollect(bool _force = false); + /// Verify block and prepare it for enactment + 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/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 07c9ba090..f142be62e 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -22,10 +22,10 @@ #include "BlockQueue.h" #include #include -#include #include #include #include "BlockChain.h" +#include "VerifiedBlock.h" #include "State.h" using namespace std; using namespace dev; @@ -37,8 +37,16 @@ const char* BlockQueueChannel::name() { return EthOrange "[]>"; } const char* BlockQueueChannel::name() { return EthOrange "▣┅▶"; } #endif +size_t const c_maxKnownCount = 100000; +size_t const c_maxKnownSize = 128 * 1024 * 1024; +size_t const c_maxUnknownCount = 100000; +size_t const c_maxUnknownSize = 512 * 1024 * 1024; // Block size can be ~50kb -BlockQueue::BlockQueue() +BlockQueue::BlockQueue(): + m_unknownSize(0), + m_knownSize(0), + m_unknownCount(0), + m_knownCount(0) { // Allow some room for other activity unsigned verifierThreads = std::max(thread::hardware_concurrency(), 3U) - 2U; @@ -57,11 +65,29 @@ BlockQueue::~BlockQueue() i.join(); } +void BlockQueue::clear() +{ + WriteGuard l(m_lock); + DEV_INVARIANT_CHECK; + Guard l2(m_verification); + m_readySet.clear(); + m_drainingSet.clear(); + m_verified.clear(); + m_unverified.clear(); + m_unknownSet.clear(); + m_unknown.clear(); + m_future.clear(); + m_unknownSize = 0; + m_unknownCount = 0; + m_knownSize = 0; + m_knownCount = 0; +} + void BlockQueue::verifierBody() { while (!m_deleting) { - std::pair work; + UnverifiedBlock work; { unique_lock l(m_verification); @@ -71,51 +97,16 @@ void BlockQueue::verifierBody() swap(work, m_unverified.front()); m_unverified.pop_front(); BlockInfo bi; - bi.mixHash = work.first; - m_verifying.push_back(make_pair(bi, bytes())); + bi.mixHash = work.hash; + bi.parentHash = work.parentHash; + m_verifying.push_back(VerifiedBlock { VerifiedBlockRef { bytesConstRef(), move(bi), Transactions() }, bytes() }); } - std::pair res; - swap(work.second, res.second); + VerifiedBlock res; + swap(work.block, res.blockData); try { - try - { - res.first.populate(res.second, CheckEverything, work.first); - res.first.verifyInternals(&res.second); - } - catch (Exception& ex) - { - clog(BlockChainNote) << " Malformed block: " << diagnostic_information(ex); - badBlock(res.second, ex.what()); - ex << errinfo_now(time(0)); - ex << errinfo_block(res.second); - if (m_onBad) - m_onBad(ex); - throw; - } - - RLP r(&res.second); - unsigned ii = 0; - for (auto const& uncle: r[2]) - { - try - { - BlockInfo().populateFromHeader(RLP(uncle.data()), CheckEverything); - } - catch (Exception& ex) - { - clog(BlockChainNote) << " Malformed block header: " << diagnostic_information(ex); - badBlockHeader(uncle.data(), ex.what()); - ex << errinfo_uncleIndex(ii); - ex << errinfo_now(time(0)); - ex << errinfo_block(res.second); - if (m_onBad) - m_onBad(ex); - throw; - } - ++ii; - } + res.verified = BlockChain::verifyBlock(res.blockData, m_onBad); } catch (...) { @@ -124,33 +115,46 @@ void BlockQueue::verifierBody() // has to be this order as that's how invariants() assumes. WriteGuard l2(m_lock); unique_lock l(m_verification); - m_readySet.erase(work.first); - m_knownBad.insert(work.first); + m_readySet.erase(work.hash); + m_knownBad.insert(work.hash); } unique_lock l(m_verification); for (auto it = m_verifying.begin(); it != m_verifying.end(); ++it) - if (it->first.mixHash == work.first) + if (it->verified.info.mixHash == work.hash) { m_verifying.erase(it); goto OK1; } - cwarn << "GAA BlockQueue corrupt: job cancelled but cannot be found in m_verifying queue."; + cwarn << "BlockQueue missing our job: was there a GM?"; OK1:; continue; } bool ready = false; { + WriteGuard l2(m_lock); unique_lock l(m_verification); - if (m_verifying.front().first.mixHash == work.first) + if (!m_verifying.empty() && m_verifying.front().verified.info.mixHash == work.hash) { // we're next! m_verifying.pop_front(); - m_verified.push_back(move(res)); - while (m_verifying.size() && !m_verifying.front().second.empty()) + if (m_knownBad.count(res.verified.info.parentHash)) { - m_verified.push_back(move(m_verifying.front())); + m_readySet.erase(res.verified.info.hash()); + m_knownBad.insert(res.verified.info.hash()); + } + else + m_verified.push_back(move(res)); + while (m_verifying.size() && !m_verifying.front().blockData.empty()) + { + if (m_knownBad.count(m_verifying.front().verified.info.parentHash)) + { + m_readySet.erase(m_verifying.front().verified.info.hash()); + m_knownBad.insert(res.verified.info.hash()); + } + else + m_verified.push_back(move(m_verifying.front())); m_verifying.pop_front(); } ready = true; @@ -158,12 +162,12 @@ void BlockQueue::verifierBody() else { for (auto& i: m_verifying) - if (i.first.mixHash == work.first) + if (i.verified.info.mixHash == work.hash) { i = move(res); goto OK; } - cwarn << "GAA BlockQueue corrupt: job finished but cannot be found in m_verifying queue."; + cwarn << "BlockQueue missing our job: was there a GM?"; OK:; } } @@ -223,6 +227,8 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo if (strftime(buf, 24, "%X", localtime(&bit)) == 0) buf[0] = '\0'; // empty if case strftime fails cblockq << "OK - queued for future [" << bi.timestamp << "vs" << time(0) << "] - will wait until" << buf; + m_unknownSize += _block.size(); + m_unknownCount++; return ImportResult::FutureTime; } else @@ -231,6 +237,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo if (m_knownBad.count(bi.parentHash)) { m_knownBad.insert(bi.hash()); + updateBad(bi.hash()); // bad parent; this is bad too, note it as such return ImportResult::BadChain; } @@ -240,6 +247,8 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo cblockq << "OK - queued as unknown parent:" << bi.parentHash; m_unknown.insert(make_pair(bi.parentHash, make_pair(h, _block.toBytes()))); m_unknownSet.insert(h); + m_unknownSize += _block.size(); + m_unknownCount++; return ImportResult::UnknownParent; } @@ -248,9 +257,11 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo // If valid, append to blocks. cblockq << "OK - ready for chain insertion."; DEV_GUARDED(m_verification) - m_unverified.push_back(make_pair(h, _block.toBytes())); + m_unverified.push_back(UnverifiedBlock { h, bi.parentHash, _block.toBytes() }); m_moreToVerify.notify_one(); m_readySet.insert(h); + m_knownSize += _block.size(); + m_knownCount++; noteReady_WITH_LOCK(h); @@ -259,30 +270,93 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo } } -bool BlockQueue::doneDrain(h256s const& _bad) +void BlockQueue::updateBad(h256 const& _bad) { - WriteGuard l(m_lock); DEV_INVARIANT_CHECK; - m_drainingSet.clear(); - if (_bad.size()) + DEV_GUARDED(m_verification) { - vector> old; - DEV_GUARDED(m_verification) - swap(m_verified, old); - for (auto& b: old) + collectUnknownBad(_bad); + bool moreBad = true; + while (moreBad) { - if (m_knownBad.count(b.first.parentHash)) - { - m_knownBad.insert(b.first.hash()); - m_readySet.erase(b.first.hash()); - } - else - DEV_GUARDED(m_verification) + moreBad = false; + std::vector oldVerified; + swap(m_verified, oldVerified); + for (auto& b: oldVerified) + if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.hash())) + { + m_knownBad.insert(b.verified.info.hash()); + m_readySet.erase(b.verified.info.hash()); + collectUnknownBad(b.verified.info.hash()); + moreBad = true; + } + else m_verified.push_back(std::move(b)); + + std::deque oldUnverified; + swap(m_unverified, oldUnverified); + for (auto& b: oldUnverified) + if (m_knownBad.count(b.parentHash) || m_knownBad.count(b.hash)) + { + m_knownBad.insert(b.hash); + m_readySet.erase(b.hash); + collectUnknownBad(b.hash); + moreBad = true; + } + else + m_unverified.push_back(std::move(b)); + + std::deque oldVerifying; + swap(m_verifying, oldVerifying); + for (auto& b: oldVerifying) + if (m_knownBad.count(b.verified.info.parentHash) || m_knownBad.count(b.verified.info.mixHash)) + { + h256 const& h = b.blockData.size() != 0 ? b.verified.info.hash() : b.verified.info.mixHash; + m_knownBad.insert(h); + m_readySet.erase(h); + collectUnknownBad(h); + moreBad = true; + } + else + m_verifying.push_back(std::move(b)); } } - m_knownBad += _bad; - return !m_readySet.empty(); + DEV_INVARIANT_CHECK; +} + +void BlockQueue::collectUnknownBad(h256 const& _bad) +{ + list badQueue(1, _bad); + while (!badQueue.empty()) + { + auto r = m_unknown.equal_range(badQueue.front()); + badQueue.pop_front(); + for (auto it = r.first; it != r.second; ++it) + { + m_unknownSize -= it->second.second.size(); + m_unknownCount--; + auto newBad = it->second.first; + m_unknownSet.erase(newBad); + m_knownBad.insert(newBad); + badQueue.push_back(newBad); + } + m_unknown.erase(r.first, r.second); + } + +} + +bool BlockQueue::doneDrain(h256s const& _bad) +{ + WriteGuard l(m_lock); + DEV_INVARIANT_CHECK; + m_drainingSet.clear(); + if (_bad.size()) + { + // at least one of them was bad. + m_knownBad += _bad; + for (h256 const& b : _bad) + updateBad(b); + } return !m_readySet.empty(); } void BlockQueue::tick(BlockChain const& _bc) @@ -306,7 +380,11 @@ void BlockQueue::tick(BlockChain const& _bc) DEV_INVARIANT_CHECK; auto end = m_future.lower_bound(t); for (auto i = m_future.begin(); i != end; ++i) + { + m_unknownSize -= i->second.second.size(); + m_unknownCount--; todo.push_back(move(i->second)); + } m_future.erase(m_future.begin(), end); } } @@ -337,12 +415,24 @@ QueueStatus BlockQueue::blockStatus(h256 const& _h) const QueueStatus::Unknown; } -void BlockQueue::drain(std::vector>& o_out, unsigned _max) +bool BlockQueue::knownFull() const +{ + return m_knownSize > c_maxKnownSize || m_knownCount > c_maxKnownCount; +} + +bool BlockQueue::unknownFull() const +{ + return m_unknownSize > c_maxUnknownSize || m_unknownCount > c_maxUnknownCount; +} + +void BlockQueue::drain(VerifiedBlocks& o_out, unsigned _max) { WriteGuard l(m_lock); DEV_INVARIANT_CHECK; + if (m_drainingSet.empty()) { + bool wasFull = knownFull(); DEV_GUARDED(m_verification) { o_out.resize(min(_max, m_verified.size())); @@ -353,11 +443,16 @@ void BlockQueue::drain(std::vector>& o_out, unsigned for (auto const& bs: o_out) { // TODO: @optimise use map rather than vector & set. - auto h = bs.first.hash(); + auto h = bs.verified.info.hash(); m_drainingSet.insert(h); m_readySet.erase(h); + m_knownSize -= bs.verified.block.size(); + m_knownCount--; } + if (wasFull && !knownFull()) + m_onRoomAvailable(); } + } bool BlockQueue::invariants() const @@ -378,7 +473,11 @@ void BlockQueue::noteReady_WITH_LOCK(h256 const& _good) for (auto it = r.first; it != r.second; ++it) { DEV_GUARDED(m_verification) - m_unverified.push_back(it->second); + m_unverified.push_back(UnverifiedBlock { it->second.first, it->first, it->second.second }); + m_knownSize += it->second.second.size(); + m_knownCount++; + m_unknownSize -= it->second.second.size(); + m_unknownCount--; auto newReady = it->second.first; m_unknownSet.erase(newReady); m_readySet.insert(newReady); @@ -389,6 +488,7 @@ void BlockQueue::noteReady_WITH_LOCK(h256 const& _good) } if (notify) m_moreToVerify.notify_all(); + DEV_INVARIANT_CHECK; } void BlockQueue::retryAllUnknown() @@ -398,18 +498,23 @@ void BlockQueue::retryAllUnknown() for (auto it = m_unknown.begin(); it != m_unknown.end(); ++it) { DEV_GUARDED(m_verification) - m_unverified.push_back(it->second); + m_unverified.push_back(UnverifiedBlock { it->second.first, it->first, it->second.second }); auto newReady = it->second.first; m_unknownSet.erase(newReady); m_readySet.insert(newReady); + m_knownCount++; m_moreToVerify.notify_one(); } m_unknown.clear(); + m_knownSize += m_unknownSize; + m_unknownSize = 0; + m_unknownCount = 0; m_moreToVerify.notify_all(); } std::ostream& dev::eth::operator<<(std::ostream& _out, BlockQueueStatus const& _bqs) { + _out << "importing: " << _bqs.importing << endl; _out << "verified: " << _bqs.verified << endl; _out << "verifying: " << _bqs.verifying << endl; _out << "unverified: " << _bqs.unverified << endl; diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index 3a299c5f6..8f079aa66 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -31,6 +31,7 @@ #include #include #include +#include "VerifiedBlock.h" namespace dev { @@ -45,6 +46,7 @@ struct BlockQueueChannel: public LogChannel { static const char* name(); static struct BlockQueueStatus { + size_t importing; size_t verified; size_t verifying; size_t unverified; @@ -74,14 +76,14 @@ public: ~BlockQueue(); /// Import a block into the queue. - ImportResult import(bytesConstRef _tx, BlockChain const& _bc, bool _isOurs = false); + ImportResult import(bytesConstRef _block, BlockChain const& _bc, bool _isOurs = false); /// Notes that time has moved on and some blocks that used to be "in the future" may no be valid. void tick(BlockChain const& _bc); /// Grabs at most @a _max of the blocks that are ready, giving them in the correct order for insertion into the chain. /// Don't forget to call doneDrain() once you're done importing. - void drain(std::vector>& o_out, unsigned _max); + void drain(std::vector& o_out, unsigned _max); /// Must be called after a drain() call. Notes that the drained blocks have been imported into the blockchain, so we can forget about them. /// @returns true iff there are additional blocks ready to be processed. @@ -97,27 +99,40 @@ public: std::pair items() const { ReadGuard l(m_lock); return std::make_pair(m_readySet.size(), m_unknownSet.size()); } /// Clear everything. - void clear() { WriteGuard l(m_lock); DEV_INVARIANT_CHECK; Guard l2(m_verification); m_readySet.clear(); m_drainingSet.clear(); m_verified.clear(); m_unverified.clear(); m_unknownSet.clear(); m_unknown.clear(); m_future.clear(); } + void clear(); /// Return first block with an unknown parent. h256 firstUnknown() const { ReadGuard l(m_lock); return m_unknownSet.size() ? *m_unknownSet.begin() : h256(); } /// Get some infomration on the current status. - BlockQueueStatus status() const { ReadGuard l(m_lock); Guard l2(m_verification); return BlockQueueStatus{m_verified.size(), m_verifying.size(), m_unverified.size(), m_future.size(), m_unknown.size(), m_knownBad.size()}; } + BlockQueueStatus status() const { ReadGuard l(m_lock); Guard l2(m_verification); return BlockQueueStatus{m_drainingSet.size(), m_verified.size(), m_verifying.size(), m_unverified.size(), m_future.size(), m_unknown.size(), m_knownBad.size()}; } /// Get some infomration on the given block's status regarding us. QueueStatus blockStatus(h256 const& _h) const; template Handler onReady(T const& _t) { return m_onReady.add(_t); } + template Handler onRoomAvailable(T const& _t) { return m_onRoomAvailable.add(_t); } template void setOnBad(T const& _t) { m_onBad = _t; } + bool knownFull() const; + bool unknownFull() const; + private: + struct UnverifiedBlock + { + h256 hash; + h256 parentHash; + bytes block; + }; + void noteReady_WITH_LOCK(h256 const& _b); bool invariants() const override; void verifierBody(); + void collectUnknownBad(h256 const& _bad); + void updateBad(h256 const& _bad); mutable boost::shared_mutex m_lock; ///< General lock for the sets, m_future and m_unknown. h256Hash m_drainingSet; ///< All blocks being imported. @@ -127,17 +142,22 @@ private: h256Hash m_knownBad; ///< Set of blocks that we know will never be valid. std::multimap> m_future; ///< Set of blocks that are not yet valid. Ordered by timestamp Signal m_onReady; ///< Called when a subsequent call to import blocks will return a non-empty container. Be nice and exit fast. + Signal m_onRoomAvailable; ///< Called when space for new blocks becomes availabe after a drain. Be nice and exit fast. mutable Mutex m_verification; ///< Mutex that allows writing to m_verified, m_verifying and m_unverified. std::condition_variable m_moreToVerify; ///< Signaled when m_unverified has a new entry. - std::vector> m_verified; ///< List of blocks, in correct order, verified and ready for chain-import. - std::deque> m_verifying; ///< List of blocks being verified; as long as the second component (bytes) is empty, it's not finished. - std::deque> m_unverified; ///< List of blocks, in correct order, ready for verification. + std::vector m_verified; ///< List of blocks, in correct order, verified and ready for chain-import. + std::deque m_verifying; ///< List of blocks being verified; as long as the block component (bytes) is empty, it's not finished. + std::deque m_unverified; ///< List of in correct order, ready for verification. std::vector m_verifiers; ///< Threads who only verify. bool m_deleting = false; ///< Exit condition for verifiers. - std::function m_onBad; ///< Called if we have a block that doesn't verify. + std::function m_onBad; ///< Called if we have a block that doesn't verify. + std::atomic m_unknownSize; ///< Tracks total size in bytes of all unknown blocks + std::atomic m_knownSize; ///< Tracks total size in bytes of all known blocks; + std::atomic m_unknownCount; ///< Tracks total count of unknown blocks. Used to avoid additional syncing + std::atomic m_knownCount; ///< Tracks total count of known blocks. Used to avoid additional syncing }; std::ostream& operator<<(std::ostream& _out, BlockQueueStatus const& _s); diff --git a/libethereum/CMakeLists.txt b/libethereum/CMakeLists.txt index 7d8f27ee7..6598e1bd7 100644 --- a/libethereum/CMakeLists.txt +++ b/libethereum/CMakeLists.txt @@ -36,6 +36,10 @@ target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES}) target_link_libraries(${EXECUTABLE} secp256k1) if (JSONRPC) target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_CLIENT_LIBRARIES}) + target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES}) + if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) + eth_copy_dlls(${EXECUTABLE} CURL_DLLS) + endif() endif() if (CMAKE_COMPILER_IS_MINGW) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 1d3539f18..31c2e8026 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -87,87 +87,100 @@ void VersionChecker::setOk() } } -void Client::onBadBlock(Exception& _ex) +void Client::onBadBlock(Exception& _ex) const { // BAD BLOCK!!! - bytes const& block = *boost::get_error_info(_ex); - if (!&block) + bytes const* block = boost::get_error_info(_ex); + if (!block) { cwarn << "ODD: onBadBlock called but exception has no block in it."; return; } - badBlock(block, _ex.what()); - cwarn << boost::diagnostic_information(_ex, true); + badBlock(*block, _ex.what()); #if ETH_JSONRPC || !ETH_TRUE - if (!m_sentinel.empty()) - { - Json::Value report; + Json::Value report; - report["client"] = "cpp"; - report["version"] = Version; - report["protocolVersion"] = c_protocolVersion; - report["databaseVersion"] = c_databaseVersion; - report["errortype"] = _ex.what(); - report["block"] = toHex(block); - report["hint"] = Json::Value(Json::objectValue); + report["client"] = "cpp"; + report["version"] = Version; + report["protocolVersion"] = c_protocolVersion; + report["databaseVersion"] = c_databaseVersion; + report["errortype"] = _ex.what(); + report["block"] = toHex(*block); - // add the various hints. - if (unsigned const* uncleIndex = boost::get_error_info(_ex)) - { - // uncle that failed. - report["hints"]["uncleIndex"] = *uncleIndex; - } - else if (unsigned const* txIndex = boost::get_error_info(_ex)) - { - // transaction that failed. - report["hints"]["transactionIndex"] = *txIndex; - } - else - { - // general block failure. - } + // add the various hints. + if (unsigned const* uncleIndex = boost::get_error_info(_ex)) + { + // uncle that failed. + report["hints"]["uncleIndex"] = *uncleIndex; + } + else if (unsigned const* txIndex = boost::get_error_info(_ex)) + { + // transaction that failed. + report["hints"]["transactionIndex"] = *txIndex; + } + else + { + // general block failure. + } - if (string const* vmtraceJson = boost::get_error_info(_ex)) - Json::Reader().parse(*vmtraceJson, report["hints"]["vmtrace"]); - if (vector const* receipts = boost::get_error_info(_ex)) - { - report["hints"]["receipts"] = Json::arrayValue; - for (auto const& r: *receipts) - report["hints"]["receipts"].append(toHex(r)); - } - if (h256Hash const* excluded = boost::get_error_info(_ex)) - { - report["hints"]["unclesExcluded"] = Json::arrayValue; - for (auto const& r: h256Set() + *excluded) - report["hints"]["unclesExcluded"].append(Json::Value(r.hex())); - } + if (string const* vmtraceJson = boost::get_error_info(_ex)) + Json::Reader().parse(*vmtraceJson, report["hints"]["vmtrace"]); + + if (vector const* receipts = boost::get_error_info(_ex)) + { + report["hints"]["receipts"] = Json::arrayValue; + for (auto const& r: *receipts) + report["hints"]["receipts"].append(toHex(r)); + } + if (h256Hash const* excluded = boost::get_error_info(_ex)) + { + report["hints"]["unclesExcluded"] = Json::arrayValue; + for (auto const& r: h256Set() + *excluded) + report["hints"]["unclesExcluded"].append(Json::Value(r.hex())); + } #define DEV_HINT_ERRINFO(X) \ - if (auto const* n = boost::get_error_info(_ex)) \ - report["hints"][#X] = toString(*n) + if (auto const* n = boost::get_error_info(_ex)) \ + report["hints"][#X] = toString(*n) #define DEV_HINT_ERRINFO_HASH(X) \ - if (auto const* n = boost::get_error_info(_ex)) \ - report["hints"][#X] = n->hex() - - DEV_HINT_ERRINFO_HASH(hash256); - DEV_HINT_ERRINFO(uncleNumber); - DEV_HINT_ERRINFO(currentNumber); - DEV_HINT_ERRINFO(now); - DEV_HINT_ERRINFO(invalidSymbol); - DEV_HINT_ERRINFO(wrongAddress); - DEV_HINT_ERRINFO(comment); - DEV_HINT_ERRINFO(min); - DEV_HINT_ERRINFO(max); - - DEV_HINT_ERRINFO(required); - DEV_HINT_ERRINFO(got); - DEV_HINT_ERRINFO_HASH(required_LogBloom); - DEV_HINT_ERRINFO_HASH(got_LogBloom); - DEV_HINT_ERRINFO_HASH(required_h256); - DEV_HINT_ERRINFO_HASH(got_h256); + if (auto const* n = boost::get_error_info(_ex)) \ + report["hints"][#X] = n->hex() + + DEV_HINT_ERRINFO_HASH(hash256); + DEV_HINT_ERRINFO(uncleNumber); + DEV_HINT_ERRINFO(currentNumber); + DEV_HINT_ERRINFO(now); + DEV_HINT_ERRINFO(invalidSymbol); + DEV_HINT_ERRINFO(wrongAddress); + DEV_HINT_ERRINFO(comment); + DEV_HINT_ERRINFO(min); + DEV_HINT_ERRINFO(max); + DEV_HINT_ERRINFO(name); + DEV_HINT_ERRINFO(field); + DEV_HINT_ERRINFO(data); + DEV_HINT_ERRINFO_HASH(nonce); + DEV_HINT_ERRINFO(difficulty); + DEV_HINT_ERRINFO(target); + DEV_HINT_ERRINFO_HASH(seedHash); + DEV_HINT_ERRINFO_HASH(mixHash); + if (tuple const* r = boost::get_error_info(_ex)) + { + report["hints"]["ethashResult"]["value"] = get<0>(*r).hex(); + report["hints"]["ethashResult"]["mixHash"] = get<1>(*r).hex(); + } + DEV_HINT_ERRINFO(required); + DEV_HINT_ERRINFO(got); + DEV_HINT_ERRINFO_HASH(required_LogBloom); + DEV_HINT_ERRINFO_HASH(got_LogBloom); + DEV_HINT_ERRINFO_HASH(required_h256); + DEV_HINT_ERRINFO_HASH(got_h256); + + cwarn << ("Report: \n" + Json::StyledWriter().write(report)); + if (!m_sentinel.empty()) + { jsonrpc::HttpClient client(m_sentinel); Sentinel rpc(client); try @@ -276,7 +289,7 @@ Client::Client(p2p::Host* _extNet, std::string const& _dbPath, WithExisting _for } Client::Client(p2p::Host* _extNet, std::shared_ptr _gp, std::string const& _dbPath, WithExisting _forceAction, u256 _networkId): - Worker("eth"), + Worker("eth", 0), m_vc(_dbPath), m_bc(_dbPath, max(m_vc.action(), _forceAction), [](unsigned d, unsigned t){ cerr << "REVISING BLOCKCHAIN: Processed " << d << " of " << t << "...\r"; }), m_gp(_gp), @@ -415,21 +428,17 @@ void Client::killChain() void Client::clearPending() { - h256Hash changeds; DEV_WRITE_GUARDED(x_postMine) { if (!m_postMine.pending().size()) return; -// for (unsigned i = 0; i < m_postMine.pending().size(); ++i) -// appendFromNewPending(m_postMine.logBloom(i), changeds); - changeds.insert(PendingChangedFilter); m_tq.clear(); DEV_READ_GUARDED(x_preMine) m_postMine = m_preMine; } startMining(); - + h256Hash changeds; noteChanged(changeds); } @@ -452,47 +461,53 @@ static S& filtersStreamOut(S& _out, T const& _fs) return _out; } -void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& io_changed, h256 _transactionHash) +void Client::appendFromNewPending(TransactionReceipt const& _receipt, h256Hash& io_changed, h256 _sha3) { Guard l(x_filtersWatches); + io_changed.insert(PendingChangedFilter); + m_specialFilters.at(PendingChangedFilter).push_back(_sha3); for (pair& i: m_filters) - if (i.second.filter.envelops(RelativeBlock::Pending, m_bc.number() + 1)) + { + // acceptable number. + auto m = i.second.filter.matches(_receipt); + if (m.size()) { - // acceptable number. - auto m = i.second.filter.matches(_receipt); - if (m.size()) - { - // filter catches them - for (LogEntry const& l: m) - i.second.changes.push_back(LocalisedLogEntry(l, m_bc.number() + 1, _transactionHash)); - io_changed.insert(i.first); - } + // filter catches them + for (LogEntry const& l: m) + i.second.changes.push_back(LocalisedLogEntry(l)); + io_changed.insert(i.first); } + } } void Client::appendFromNewBlock(h256 const& _block, h256Hash& io_changed) { // TODO: more precise check on whether the txs match. auto d = m_bc.info(_block); - auto br = m_bc.receipts(_block); + auto receipts = m_bc.receipts(_block).receipts; Guard l(x_filtersWatches); + io_changed.insert(ChainChangedFilter); + m_specialFilters.at(ChainChangedFilter).push_back(_block); for (pair& i: m_filters) - if (i.second.filter.envelops(RelativeBlock::Latest, d.number) && i.second.filter.matches(d.logBloom)) - // acceptable number & looks like block may contain a matching log entry. - for (size_t j = 0; j < br.receipts.size(); j++) + { + // acceptable number & looks like block may contain a matching log entry. + unsigned logIndex = 0; + for (size_t j = 0; j < receipts.size(); j++) + { + logIndex++; + auto tr = receipts[j]; + auto m = i.second.filter.matches(tr); + if (m.size()) { - auto tr = br.receipts[j]; - auto m = i.second.filter.matches(tr); - if (m.size()) - { - auto transactionHash = transaction(d.hash(), j).sha3(); - // filter catches them - for (LogEntry const& l: m) - i.second.changes.push_back(LocalisedLogEntry(l, (unsigned)d.number, transactionHash)); - io_changed.insert(i.first); - } + auto transactionHash = transaction(d.hash(), j).sha3(); + // filter catches them + for (LogEntry const& l: m) + i.second.changes.push_back(LocalisedLogEntry(l, d, transactionHash, j, logIndex)); + io_changed.insert(i.first); } + } + } } void Client::setForceMining(bool _enable) @@ -596,16 +611,26 @@ 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 = 1; + void Client::syncBlockQueue() { ImportRoute ir; - cwork << "BQ ==> CHAIN ==> STATE"; - { - tie(ir.first, ir.second, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, rand() % 90 + 10); - if (ir.first.empty()) - return; - } + 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 > c_targetDuration * 1.1 && m_syncAmount > c_syncMin) + m_syncAmount = max(c_syncMin, m_syncAmount * 9 / 10); + 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; onChainChanged(ir); } @@ -630,7 +655,7 @@ void Client::syncTransactionQueue() DEV_READ_GUARDED(x_postMine) for (size_t i = 0; i < newPendingReceipts.size(); i++) appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); - changeds.insert(PendingChangedFilter); + // Tell farm about new transaction (i.e. restartProofOfWork mining). onPostStateChanged(); @@ -673,47 +698,49 @@ void Client::onChainChanged(ImportRoute const& _ir) h256Hash changeds; for (auto const& h: _ir.first) appendFromNewBlock(h, changeds); - changeds.insert(ChainChangedFilter); // 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); } @@ -779,15 +806,18 @@ void Client::noteChanged(h256Hash const& _filters) cwatch << "!!!" << w.first << w.second.id.abridged(); w.second.changes += m_filters.at(w.second.id).changes; } - else - { - cwatch << "!!!" << w.first << LogTag::Special << (w.second.id == PendingChangedFilter ? "pending" : w.second.id == ChainChangedFilter ? "chain" : "???"); - w.second.changes.push_back(LocalisedLogEntry(SpecialLogEntry, 0)); - } + else if (m_specialFilters.count(w.second.id)) + for (h256 const& hash: m_specialFilters.at(w.second.id)) + { + cwatch << "!!!" << w.first << LogTag::Special << (w.second.id == PendingChangedFilter ? "pending" : w.second.id == ChainChangedFilter ? "chain" : "???"); + w.second.changes.push_back(LocalisedLogEntry(SpecialLogEntry, hash)); + } } // clear the filters now. for (auto& i: m_filters) i.second.changes.clear(); + for (auto& i: m_specialFilters) + i.second.clear(); } void Client::doWork() @@ -847,7 +877,16 @@ void Client::checkWatchGarbage() State Client::asOf(h256 const& _block) const { - return State(m_stateDB, bc(), _block); + try + { + return State(m_stateDB, bc(), _block); + } + catch (Exception& ex) + { + ex << errinfo_block(bc().block(_block)); + onBadBlock(ex); + return State(); + } } void Client::prepareForTransaction() @@ -878,8 +917,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 2de6e9403..b70f01155 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; } @@ -301,7 +301,7 @@ private: /// Called when we have attempted to import a bad block. /// @warning May be called from any thread. - void onBadBlock(Exception& _ex); + void onBadBlock(Exception& _ex) const; VersionChecker m_vc; ///< Dummy object to check & update the protocol version. CanonBlockChain m_bc; ///< Maintains block database. @@ -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/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index 6a2c76c0b..d5bc0dbb9 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -45,19 +45,21 @@ State ClientBase::asOf(BlockNumber _h) const return asOf(bc().numberHash(_h)); } -void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) +void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, u256 _nonce) { 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); + 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) +{ + auto a = toAddress(_secret); + 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) @@ -171,8 +173,8 @@ LocalisedLogEntries ClientBase::logs(unsigned _watchId) const LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const { LocalisedLogEntries ret; - unsigned begin = min(bc().number() + 1, (unsigned)_f.latest()); - unsigned end = min(bc().number(), min(begin, (unsigned)_f.earliest())); + unsigned begin = min(bc().number() + 1, (unsigned)numberFromHash(_f.latest())); + unsigned end = min(bc().number(), min(begin, (unsigned)numberFromHash(_f.earliest()))); // Handle pending transactions differently as they're not on the block chain. if (begin > bc().number()) @@ -182,11 +184,10 @@ LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const { // Might have a transaction that contains a matching log. TransactionReceipt const& tr = temp.receipt(i); - auto th = temp.pending()[i].sha3(); LogEntries le = _f.matches(tr); if (le.size()) for (unsigned j = 0; j < le.size(); ++j) - ret.insert(ret.begin(), LocalisedLogEntry(le[j], begin, th)); + ret.insert(ret.begin(), LocalisedLogEntry(le[j])); } begin = bc().number(); } @@ -201,20 +202,22 @@ LocalisedLogEntries ClientBase::logs(LogFilter const& _f) const { int total = 0; auto h = bc().numberHash(n); + auto info = bc().info(h); auto receipts = bc().receipts(h).receipts; + unsigned logIndex = 0; for (size_t i = 0; i < receipts.size(); i++) { + logIndex++; TransactionReceipt receipt = receipts[i]; if (_f.matches(receipt.bloom())) { - auto info = bc().info(h); auto th = transaction(info.hash(), i).sha3(); LogEntries le = _f.matches(receipt); if (le.size()) { total += le.size(); for (unsigned j = 0; j < le.size(); ++j) - ret.insert(ret.begin(), LocalisedLogEntry(le[j], n, th)); + ret.insert(ret.begin(), LocalisedLogEntry(le[j], info, th, i, logIndex)); } } @@ -313,6 +316,8 @@ LocalisedLogEntries ClientBase::checkWatch(unsigned _watchId) BlockInfo ClientBase::blockInfo(h256 _hash) const { + if (_hash == PendingBlockHash) + return preMine().info(); return BlockInfo(bc().block(_hash)); } @@ -441,6 +446,24 @@ h256 ClientBase::hashFromNumber(BlockNumber _number) const BlockNumber ClientBase::numberFromHash(h256 _blockHash) const { + if (_blockHash == PendingBlockHash) + return bc().number() + 1; + else if (_blockHash == LatestBlockHash) + return bc().number(); + else if (_blockHash == EarliestBlockHash) + return 0; return bc().number(_blockHash); } +int ClientBase::compareBlockHashes(h256 _h1, h256 _h2) const +{ + BlockNumber n1 = numberFromHash(_h1); + BlockNumber n2 = numberFromHash(_h2); + + if (n1 > n2) { + return 1; + } else if (n1 == n2) { + return 0; + } + return -1; +} diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index b2afe3597..8aa84101c 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -44,7 +44,7 @@ static const h256 PendingChangedFilter = u256(0); static const h256 ChainChangedFilter = u256(1); static const LogEntry SpecialLogEntry = LogEntry(Address(), h256s(), bytes()); -static const LocalisedLogEntry InitialChange(SpecialLogEntry, 0); +static const LocalisedLogEntry InitialChange(SpecialLogEntry); struct ClientWatch { @@ -76,6 +76,7 @@ public: virtual ~ClientBase() {} /// Submits the given message-call transaction. + virtual void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice, u256 _nonce); virtual void submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data = bytes(), u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override; /// Submits a new contract-creation transaction. @@ -117,6 +118,7 @@ public: virtual h256 hashFromNumber(BlockNumber _number) const override; virtual BlockNumber numberFromHash(h256 _blockHash) const override; + virtual int compareBlockHashes(h256 _h1, h256 _h2) const override; virtual BlockInfo blockInfo(h256 _hash) const override; virtual BlockDetails blockDetails(h256 _hash) const override; virtual Transaction transaction(h256 _transactionHash) const override; @@ -175,6 +177,8 @@ protected: // filters mutable Mutex x_filtersWatches; ///< Our lock. std::unordered_map m_filters; ///< The dictionary of filters that are active. + std::unordered_map m_specialFilters = std::unordered_map>{{PendingChangedFilter, {}}, {ChainChangedFilter, {}}}; + ///< The dictionary of special filters and their additional data std::map m_watches; ///< Each and every watch - these reference a filter. }; diff --git a/libethereum/CommonNet.h b/libethereum/CommonNet.h index 1515c844d..b960c8f3f 100644 --- a/libethereum/CommonNet.h +++ b/libethereum/CommonNet.h @@ -38,9 +38,9 @@ namespace eth #if ETH_DEBUG static const unsigned c_maxHashes = 2048; ///< Maximum number of hashes BlockHashes will ever send. -static const unsigned c_maxHashesAsk = 256; ///< Maximum number of hashes GetBlockHashes will ever ask for. +static const unsigned c_maxHashesAsk = 2048; ///< Maximum number of hashes GetBlockHashes will ever ask for. static const unsigned c_maxBlocks = 128; ///< Maximum number of blocks Blocks will ever send. -static const unsigned c_maxBlocksAsk = 8; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain). +static const unsigned c_maxBlocksAsk = 128; ///< Maximum number of blocks we ask to receive in Blocks (when using GetChain). static const unsigned c_maxPayload = 262144; ///< Maximum size of packet for us to send. #else static const unsigned c_maxHashes = 2048; ///< Maximum number of hashes BlockHashes will ever send. @@ -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 d205394ac..67a21d36a 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -39,6 +39,9 @@ using namespace dev::eth; 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(), @@ -48,8 +51,10 @@ 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; }); } EthereumHost::~EthereumHost() @@ -77,8 +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; + setState(SyncState::HashesNegotiate); m_syncingLatestHash = h256(); m_syncingTotalDifficulty = 0; m_latestBlockSent = h256(); @@ -86,12 +90,28 @@ void EthereumHost::reset() m_hashes.clear(); } +void EthereumHost::resetSyncTo(h256 const& _h) +{ + setState(SyncState::HashesNegotiate); + m_syncingLatestHash = _h; +} + + +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() { bool netChange = ensureInitialised(); auto h = m_chain.currentHash(); // If we've finished our initial sync (including getting all the blocks into the chain so as to reduce invalid transactions), start trading transactions & blocks - if (isSyncing() && m_chain.isKnown(m_latestBlockSent)) + if (!isSyncing() && m_chain.isKnown(m_latestBlockSent)) { if (m_newTransactions) { @@ -105,6 +125,13 @@ void EthereumHost::doWork() } } + if (m_continueSync) + { + m_continueSync = false; + RecursiveGuard l(x_sync); + continueSync(); + } + foreachPeer([](EthereumPeer* _p) { _p->tick(); }); // return netChange; @@ -144,6 +171,7 @@ void EthereumHost::maintainTransactions() RLPStream ts; _p->prep(ts, TransactionsPacket, n).appendRaw(b, n); _p->sealAndSend(ts); + cnote << "Sent" << n << "transactions to " << _p->session()->info().clientVersion; } _p->m_requireTransactions = false; }); @@ -238,6 +266,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) @@ -250,49 +279,50 @@ void EthereumHost::onPeerStatus(EthereumPeer* _peer) _peer->disable("Peer banned for previous bad behaviour."); else { - if (_peer->m_protocolVersion != protocolVersion()) - estimatePeerHashes(_peer); - else + unsigned estimatedHashes = estimateHashes(); + if (_peer->m_protocolVersion == protocolVersion()) { if (_peer->m_latestBlockNumber > m_chain.number()) _peer->m_expectedHashes = (unsigned)_peer->m_latestBlockNumber - m_chain.number(); - if (m_hashMan.chainSize() < _peer->m_expectedHashes) + if (_peer->m_expectedHashes > estimatedHashes) + _peer->disable("Too many hashes"); + 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; } -void EthereumHost::estimatePeerHashes(EthereumPeer* _peer) +unsigned EthereumHost::estimateHashes() { BlockInfo block = m_chain.info(); time_t lastBlockTime = (block.hash() == m_chain.genesisHash()) ? 1428192000 : (time_t)block.timestamp; time_t now = time(0); - unsigned blockCount = 30000; + unsigned blockCount = c_chainReorgSize; if (lastBlockTime > now) clog(NetWarn) << "Clock skew? Latest block is in the future"; else blockCount += (now - lastBlockTime) / (unsigned)c_durationLimit; clog(NetAllDetail) << "Estimated hashes: " << blockCount; - _peer->m_expectedHashes = blockCount; -} - -void EthereumHost::noteRude(p2p::NodeId const& _id, std::string const& _client) -{ - cwarn << "RUDE node/client: " << _id << _client; - m_rudeNodes.insert(_id); - m_rudeClients.insert(_client); + return blockCount; } void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) { RecursiveGuard l(x_sync); - assert(_peer->m_asking == Asking::Nothing); + if (_peer->m_syncHashNumber > 0) + _peer->m_syncHashNumber += _hashes.size(); + + _peer->setAsking(Asking::Nothing); onPeerHashes(_peer, _hashes, false); } void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool _complete) { + DEV_INVARIANT_CHECK; if (_hashes.empty()) { _peer->m_hashSub.doneFetch(); @@ -301,7 +331,7 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool } bool syncByNumber = _peer->m_syncHashNumber; - if (!syncByNumber && _peer->m_syncHash != m_syncingLatestHash) + if (!syncByNumber && !_complete && _peer->m_syncHash != m_syncingLatestHash) { // Obsolete hashes, discard continueSync(_peer); @@ -359,47 +389,53 @@ void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool } if (_complete) { - m_needSyncBlocks = true; + clog(NetMessageSummary) << "Start new blocks download..."; + m_syncingLatestHash = h256(); + setState(SyncState::NewBlocks); + m_man.resetToChain(m_hashes); + m_hashes.clear(); + m_hashMan.reset(m_chain.number() + 1); continueSync(_peer); } 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); - assert(_peer->m_asking == Asking::Nothing); + DEV_INVARIANT_CHECK; + _peer->setAsking(Asking::Nothing); unsigned itemCount = _r.itemCount(); clog(NetMessageSummary) << "Blocks (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreBlocks"); @@ -418,6 +454,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) { @@ -446,6 +483,7 @@ void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) break; case ImportResult::UnknownParent: + lastUnknown = h; unknown++; break; @@ -461,34 +499,36 @@ 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_man.isComplete() && !m_needSyncHashes) + if (m_state == SyncState::NewBlocks && unknown > 0) { - // Done our chain-get. - m_needSyncBlocks = false; - clog(NetNote) << "Chain download complete."; - // 1/100th for each useful block hash. - _peer->addRating(m_man.chainSize() / 100); //TODO: what about other peers? - m_man.reset(); + _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()) + DEV_INVARIANT_CHECK; + if (isSyncing() || _peer->isConversing()) { clog(NetMessageSummary) << "Ignoring new hashes since we're already downloading."; return; } 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()) + DEV_INVARIANT_CHECK; + if ((isSyncing() || _peer->isConversing()) && m_state != SyncState::NewBlocks) { clog(NetMessageSummary) << "Ignoring new blocks since we're already downloading."; return; @@ -528,9 +568,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; } } @@ -542,8 +580,9 @@ void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) _peer->m_knownBlocks.insert(h); if (sync) - continueSync(_peer); + continueSync(); } + DEV_INVARIANT_CHECK; } void EthereumHost::onPeerTransactions(EthereumPeer* _peer, RLP const& _r) @@ -577,17 +616,20 @@ void EthereumHost::onPeerTransactions(EthereumPeer* _peer, RLP const& _r) void EthereumHost::onPeerAborting(EthereumPeer* _peer) { RecursiveGuard l(x_sync); - if (_peer->isSyncing()) + if (_peer->isConversing()) { _peer->setIdle(); - _peer->setRude(); + if (_peer->isCriticalSyncing()) + _peer->setRude(); continueSync(); } } void EthereumHost::continueSync() { - clog(NetAllDetail) << "Getting help with downloading hashes and blocks"; + if (m_state == SyncState::WaitingQueue) + setState(m_lastActiveState); + clog(NetAllDetail) << "Continuing sync for all peers"; foreachPeer([&](EthereumPeer* _p) { if (_p->m_asking == Asking::Nothing) @@ -597,11 +639,18 @@ 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 && peerShouldGrabChain(_peer)) + if (needHashes()) { + if (!peerShouldGrabChain(_peer)) + { + _peer->setIdle(); + return; + } + foreachPeer([&](EthereumPeer* _p) { if (_p != _peer && _p->m_asking == Asking::Hashes) @@ -626,7 +675,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 @@ -640,25 +689,63 @@ void EthereumHost::continueSync(EthereumPeer* _peer) if (_peer->m_totalDifficulty >= m_syncingTotalDifficulty) { _peer->requestHashes(m_syncingLatestHash); - m_syncingV61 = false; - m_estimatedHashes = _peer->m_expectedHashes; + setState(SyncState::HashesSingle); + m_estimatedHashes = _peer->m_expectedHashes - (_peer->m_protocolVersion == protocolVersion() ? 0 : c_chainReorgSize); } else _peer->setIdle(); } } - else if (m_needSyncBlocks && peerShouldGrabBlocks(_peer)) // Check if this peer can help with downloading blocks - _peer->requestBlocks(); + else if (needBlocks()) + { + if (m_man.isComplete()) + { + // Done our chain-get. + 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? + m_man.reset(); + _peer->setIdle(); + return; + } + else if (peerCanHelp(_peer)) + { + // Check block queue status + if (m_bq.unknownFull()) + { + clog(NetWarn) << "Too many unknown blocks, restarting sync"; + m_bq.clear(); + reset(); + continueSync(); + } + else if (m_bq.knownFull()) + { + clog(NetAllDetail) << "Waiting for block queue before downloading blocks"; + m_lastActiveState = m_state; + setState(SyncState::WaitingQueue); + _peer->setIdle(); + } + else + _peer->requestBlocks(); + } + } else _peer->setIdle(); + DEV_INVARIANT_CHECK; } -bool EthereumHost::peerShouldGrabBlocks(EthereumPeer* _peer) const +bool EthereumHost::peerCanHelp(EthereumPeer* _peer) const { - // Early exit if this peer has proved unreliable. - if (_peer->isRude()) - return false; + (void)_peer; + return true; +} +bool EthereumHost::peerShouldGrabBlocks(EthereumPeer* _peer) const +{ + // this is only good for deciding whether to go ahead and grab a particular peer's hash chain, + // yet it's being used in determining whether to allow a peer help with downloading an existing + // chain of blocks. auto td = _peer->m_totalDifficulty; auto lh = m_syncingLatestHash; auto ctd = m_chain.details().totalDifficulty; @@ -692,24 +779,42 @@ bool EthereumHost::peerShouldGrabChain(EthereumPeer* _peer) const } } -bool EthereumHost::isSyncing_UNSAFE() const +bool EthereumHost::isSyncing() const { - /// We need actual peer information here to handle the case when we are the first ever peer on the network to mine. - /// I.e. on a new private network the first node mining has noone to sync with and should start block propogation immediately. - bool syncing = false; - foreachPeer([&](EthereumPeer* _p) - { - if (_p->m_asking != Asking::Nothing) - syncing = true; - }); - return syncing; + 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, static_cast(m_hashes.size()), true }; + 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 8c25a86c6..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,10 +71,8 @@ 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 noteRude(p2p::NodeId const& _id, std::string const& _client); - bool isRude(p2p::NodeId const& _id, std::string const& _client) const { return m_rudeClients.count(_client) && m_rudeNodes.count(_id); } void noteNewTransactions() { m_newTransactions = true; } void noteNewBlocks() { m_newBlocks = true; } @@ -89,16 +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(); @@ -126,11 +130,17 @@ private: void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes, bool _complete); bool peerShouldGrabBlocks(EthereumPeer* _peer) const; bool peerShouldGrabChain(EthereumPeer* _peer) const; + 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. BlockQueue& m_bq; ///< Maintains a list of incoming blocks not yet on the blockchain (to be imported). + Handler m_bqRoomAvailable; u256 m_networkId; @@ -146,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. - 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. - std::unordered_set m_rudeNodes; ///< Nodes that were impolite while syncing. We avoid syncing from these if possible. - std::unordered_set m_rudeClients; ///< Nodes that were impolite while syncing. We avoid syncing from these if possible. + 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. }; } diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index 497513b46..7a30f1ad9 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "BlockChain.h" #include "EthereumHost.h" #include "TransactionQueue.h" @@ -40,8 +41,7 @@ EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h, unsigned _i, Cap m_hashSub(host()->hashDownloadMan()), m_peerCapabilityVersion(_cap.second) { - m_isRude = host()->isRude(session()->id(), session()->info().clientVersion); - session()->addNote("manners", m_isRude ? "RUDE" : "nice"); + session()->addNote("manners", isRude() ? "RUDE" : "nice"); m_syncHashNumber = host()->chain().number() + 1; requestStatus(); } @@ -52,16 +52,20 @@ EthereumPeer::~EthereumPeer() abortSync(); } -void EthereumPeer::abortSync() +bool EthereumPeer::isRude() const { - host()->onPeerAborting(this); + return repMan().isRude(*session(), name()); } void EthereumPeer::setRude() { - m_isRude = true; - host()->noteRude(session()->id(), session()->info().clientVersion); - session()->addNote("manners", m_isRude ? "RUDE" : "nice"); + repMan().noteRude(*session(), name()); + session()->addNote("manners", "RUDE"); +} + +void EthereumPeer::abortSync() +{ + host()->onPeerAborting(this); } EthereumHost* EthereumPeer::host() const @@ -136,7 +140,7 @@ void EthereumPeer::requestHashes(h256 const& _lastHash) void EthereumPeer::requestBlocks() { setAsking(Asking::Blocks); - auto blocks = m_sub.nextFetch(c_maxBlocksAsk); + auto blocks = m_sub.nextFetch(isRude() ? 1 : c_maxBlocksAsk); if (blocks.size()) { RLPStream s; @@ -156,7 +160,7 @@ void EthereumPeer::setAsking(Asking _a) m_lastAsk = chrono::system_clock::now(); session()->addNote("ask", _a == Asking::Nothing ? "nothing" : _a == Asking::State ? "state" : _a == Asking::Hashes ? "hashes" : _a == Asking::Blocks ? "blocks" : "?"); - session()->addNote("sync", string(isSyncing() ? "ongoing" : "holding") + (needsSyncing() ? " & needed" : "")); + session()->addNote("sync", string(isCriticalSyncing() ? "ONGOING" : "holding") + (needsSyncing() ? " & needed" : "")); } void EthereumPeer::tick() @@ -166,11 +170,16 @@ void EthereumPeer::tick() session()->disconnect(PingTimeout); } -bool EthereumPeer::isSyncing() const +bool EthereumPeer::isConversing() const { return m_asking != Asking::Nothing; } +bool EthereumPeer::isCriticalSyncing() const +{ + return m_asking == Asking::Hashes || m_asking == Asking::State || (m_asking == Asking::Blocks && m_protocolVersion == 60); +} + bool EthereumPeer::interpret(unsigned _id, RLP const& _r) { try @@ -256,13 +265,10 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) clog(NetWarn) << "Peer giving us hashes when we didn't ask for them."; break; } - setAsking(Asking::Nothing); h256s hashes(itemCount); for (unsigned i = 0; i < itemCount; ++i) hashes[i] = _r[i].toHash(); - if (m_syncHashNumber > 0) - m_syncHashNumber += itemCount; host()->onPeerHashes(this, hashes); break; } @@ -305,10 +311,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) if (m_asking != Asking::Blocks) clog(NetImpolite) << "Peer giving us blocks when we didn't ask for them."; else - { - setAsking(Asking::Nothing); host()->onPeerBlocks(this, _r); - } break; } case NewBlockPacket: diff --git a/libethereum/EthereumPeer.h b/libethereum/EthereumPeer.h index 128612f29..a12b7a197 100644 --- a/libethereum/EthereumPeer.h +++ b/libethereum/EthereumPeer.h @@ -83,7 +83,7 @@ public: void requestBlocks(); /// Check if this node is rude. - bool isRude() const { return m_isRude; } + bool isRude() const; /// Set that it's a rude node. void setRude(); @@ -109,8 +109,11 @@ private: /// Do we presently need syncing with this peer? bool needsSyncing() const { return !isRude() && !!m_latestHash; } - /// Are we presently syncing with this peer? - bool isSyncing() const; + /// Are we presently in the process of communicating with this peer? + bool isConversing() const; + + /// Are we presently in a critical part of the syncing process with this peer? + bool isCriticalSyncing() const; /// Runs period checks to check up on the peer. void tick(); @@ -152,8 +155,6 @@ private: h256Hash m_knownBlocks; ///< Blocks that the peer already knows about (that don't need to be sent to them). Mutex x_knownTransactions; h256Hash m_knownTransactions; ///< Transactions that the peer already knows of. - - bool m_isRude; ///< True if this node has been rude in the past. }; } diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index e89334370..9bf0cc74f 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -46,6 +46,8 @@ bool changesMemory(Instruction _inst) return _inst == Instruction::MSTORE || _inst == Instruction::MSTORE8 || + _inst == Instruction::MLOAD || + _inst == Instruction::CREATE || _inst == Instruction::CALL || _inst == Instruction::CALLCODE || _inst == Instruction::SHA3 || @@ -71,6 +73,7 @@ void StandardTrace::operator()(uint64_t _steps, Instruction inst, bigint newMemS stack.append(toHex(toCompactBigEndian(i), 1)); r["stack"] = stack; + bool returned = false; bool newContext = false; Instruction lastInst = Instruction::STOP; @@ -84,6 +87,7 @@ void StandardTrace::operator()(uint64_t _steps, Instruction inst, bigint newMemS else if (m_lastInst.size() == ext.depth + 2) { // returned from old context + returned = true; m_lastInst.pop_back(); lastInst = m_lastInst.back(); } @@ -91,6 +95,7 @@ void StandardTrace::operator()(uint64_t _steps, Instruction inst, bigint newMemS { // continuing in previous context lastInst = m_lastInst.back(); + m_lastInst.back() = inst; } else { @@ -101,10 +106,10 @@ void StandardTrace::operator()(uint64_t _steps, Instruction inst, bigint newMemS if (changesMemory(lastInst) || newContext) { - Json::Value mem(Json::arrayValue); - for (auto const& i: vm.memory()) - mem.append(toHex(toCompactBigEndian(i), 1)); - r["memory"] = mem; + if (vm.memory().size() < 1024) + r["memory"] = toHex(vm.memory()); + else + r["sha3memory"] = sha3(vm.memory()).hex(); } if (changesStorage(lastInst) || newContext) @@ -115,21 +120,26 @@ void StandardTrace::operator()(uint64_t _steps, Instruction inst, bigint newMemS r["storage"] = storage; } - r["depth"] = ext.depth; - r["address"] = ext.myAddress.hex(); + if (returned || newContext) + r["depth"] = ext.depth; + if (newContext) + r["address"] = ext.myAddress.hex(); r["steps"] = (unsigned)_steps; r["inst"] = (unsigned)inst; + if (m_showMnemonics) + r["instname"] = instructionInfo(inst).name; r["pc"] = toString(vm.curPC()); r["gas"] = toString(gas); r["gascost"] = toString(gasCost); - r["memexpand"] = toString(newMemSize); + if (!!newMemSize) + r["memexpand"] = toString(newMemSize); m_trace->append(r); } -string StandardTrace::json() const +string StandardTrace::json(bool _styled) const { - return Json::FastWriter().write(*m_trace); + return _styled ? Json::StyledWriter().write(*m_trace) : Json::FastWriter().write(*m_trace); } Executive::Executive(State& _s, BlockChain const& _bc, unsigned _level): @@ -191,12 +201,12 @@ void Executive::initialize(Transaction const& _transaction) // Avoid unaffordable transactions. m_gasCost = (bigint)m_t.gas() * m_t.gasPrice(); - m_totalCost = m_t.value() + m_gasCost; - if (m_s.balance(m_t.sender()) < m_totalCost) + bigint totalCost = m_t.value() + m_gasCost; + if (m_s.balance(m_t.sender()) < totalCost) { - clog(ExecutiveWarnChannel) << "Not enough cash: Require >" << m_totalCost << " Got" << m_s.balance(m_t.sender()) << "for sender: " << m_t.sender(); + clog(ExecutiveWarnChannel) << "Not enough cash: Require >" << totalCost << " Got" << m_s.balance(m_t.sender()) << "for sender: " << m_t.sender(); m_excepted = TransactionException::NotEnoughCash; - BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError(m_totalCost, (bigint)m_s.balance(m_t.sender())) << errinfo_comment(m_t.sender().abridged())); + BOOST_THROW_EXCEPTION(NotEnoughCash() << RequirementError(totalCost, (bigint)m_s.balance(m_t.sender())) << errinfo_comment(m_t.sender().abridged())); } } @@ -249,7 +259,8 @@ bool Executive::call(CallParameters const& _p, u256 const& _gasPrice, Address co { m_outRef = _p.out; // Save ref to expected output buffer to be used in go() bytes const& c = m_s.code(_p.codeAddress); - m_ext = make_shared(m_s, m_lastHashes, _p.receiveAddress, _p.senderAddress, _origin, _p.value, _gasPrice, _p.data, &c, m_depth); + h256 codeHash = m_s.codeHash(_p.codeAddress); + m_ext = make_shared(m_s, m_lastHashes, _p.receiveAddress, _p.senderAddress, _origin, _p.value, _gasPrice, _p.data, &c, codeHash, m_depth); } } @@ -269,7 +280,7 @@ bool Executive::create(Address _sender, u256 _endowment, u256 _gasPrice, u256 _g // Execute _init. if (!_init.empty()) - m_ext = make_shared(m_s, m_lastHashes, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, m_depth); + m_ext = make_shared(m_s, m_lastHashes, m_newAddress, _sender, _origin, _endowment, _gasPrice, bytesConstRef(), _init, sha3(_init), m_depth); m_s.m_cache[m_newAddress] = Account(m_s.balance(m_newAddress), Account::ContractConception); m_s.transferBalance(_sender, m_newAddress, _endowment); diff --git a/libethereum/Executive.h b/libethereum/Executive.h index e2c910cd0..4976ce03a 100644 --- a/libethereum/Executive.h +++ b/libethereum/Executive.h @@ -49,9 +49,12 @@ public: StandardTrace(); void operator()(uint64_t _steps, Instruction _inst, bigint _newMemSize, bigint _gasCost, bigint _gas, VM* _vm, ExtVMFace const* _extVM); - std::string json() const; + void setShowMnemonics() { m_showMnemonics = true; } + + std::string json(bool _styled = false) const; private: + bool m_showMnemonics = false; std::vector m_lastInst; std::shared_ptr m_trace; }; @@ -83,8 +86,6 @@ public: Executive(State& _s, LastHashes const& _lh, unsigned _level = 0): m_s(_s), m_lastHashes(_lh), m_depth(_level) {} /// Basic constructor. Executive(State& _s, BlockChain const& _bc, unsigned _level = 0); - /// Basic destructor. - ~Executive() = default; Executive(Executive const&) = delete; void operator=(Executive) = delete; @@ -142,7 +143,7 @@ public: private: State& m_s; ///< The state to which this operation/transaction is applied. LastHashes m_lastHashes; - std::shared_ptr m_ext; ///< The VM externality object for the VM execution or null if no VM is required. + std::shared_ptr m_ext; ///< The VM externality object for the VM execution or null if no VM is required. shared_ptr used only to allow ExtVM forward reference. bytesRef m_outRef; ///< Reference to "expected output" buffer. ExecutionResult* m_res = nullptr; ///< Optional storage for execution results. Address m_newAddress; ///< The address of the created contract in the case of create() being called. @@ -155,9 +156,7 @@ private: Transaction m_t; ///< The original transaction. Set by setup(). LogEntries m_logs; ///< The log entries created by this transaction. Set by finalize(). - bigint m_gasRequired; ///< Gas required during execution of the transaction. bigint m_gasCost; - bigint m_totalCost; }; } diff --git a/libethereum/ExtVM.cpp b/libethereum/ExtVM.cpp index 782d4d79c..305462511 100644 --- a/libethereum/ExtVM.cpp +++ b/libethereum/ExtVM.cpp @@ -20,18 +20,69 @@ */ #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; + +/// 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) +{ + // 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, [&]{ + try + { + _e.go(_onOp); + } + catch (...) + { + exception = std::current_exception(); // Catch all exceptions to be rethrown in parent thread. + } + }}.join(); + if (exception) + std::rethrow_exception(exception); +} + +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 + _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 +98,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(); diff --git a/libethereum/ExtVM.h b/libethereum/ExtVM.h index babff4edf..853787493 100644 --- a/libethereum/ExtVM.h +++ b/libethereum/ExtVM.h @@ -39,8 +39,8 @@ class ExtVM: public ExtVMFace { public: /// Full constructor. - ExtVM(State& _s, LastHashes const& _lh, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, unsigned _depth = 0): - ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _s.m_previousBlock, _s.m_currentBlock, _lh, _depth), m_s(_s), m_origCache(_s.m_cache) + ExtVM(State& _s, LastHashes const& _lh, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytesConstRef _code, h256 const& _codeHash, unsigned _depth = 0): + ExtVMFace(_myAddress, _caller, _origin, _value, _gasPrice, _data, _code.toBytes(), _codeHash, _s.m_previousBlock, _s.m_currentBlock, _lh, _depth), m_s(_s), m_origCache(_s.m_cache) { m_s.ensureCached(_myAddress, true, true); } diff --git a/libethereum/Interface.h b/libethereum/Interface.h index 636f73fbf..f631fb43e 100644 --- a/libethereum/Interface.h +++ b/libethereum/Interface.h @@ -137,6 +137,7 @@ public: virtual std::pair transactionLocation(h256 const& _transactionHash) const = 0; virtual h256 hashFromNumber(BlockNumber _number) const = 0; virtual BlockNumber numberFromHash(h256 _blockHash) const = 0; + virtual int compareBlockHashes(h256 _h1, h256 _h2) const = 0; virtual BlockInfo blockInfo(h256 _hash) const = 0; virtual BlockDetails blockDetails(h256 _hash) const = 0; diff --git a/libethereum/LogFilter.cpp b/libethereum/LogFilter.cpp index 21ba9d3ef..6e0fbd709 100644 --- a/libethereum/LogFilter.cpp +++ b/libethereum/LogFilter.cpp @@ -46,33 +46,6 @@ h256 LogFilter::sha3() const return dev::sha3(s.out()); } -static bool isNoLater(RelativeBlock _logBlockRelation, u256 _logBlockNumber, unsigned _latest) -{ - if (_latest == PendingBlock) - return true; - else if (_latest == LatestBlock) - return _logBlockRelation == RelativeBlock::Latest; - else - return _logBlockNumber <= _latest; -} - -static bool isNoEarlier(RelativeBlock _logBlockRelation, u256 _logBlockNumber, unsigned _earliest) -{ - if (_earliest == PendingBlock) - return _logBlockRelation == RelativeBlock::Pending; - else if (_earliest == LatestBlock) - return true; - else - return _logBlockNumber >= _earliest; -} - -bool LogFilter::envelops(RelativeBlock _logBlockRelation, u256 _logBlockNumber) const -{ - return - isNoLater(_logBlockRelation, _logBlockNumber, m_latest) && - isNoEarlier(_logBlockRelation, _logBlockNumber, m_earliest); -} - bool LogFilter::matches(LogBloom _bloom) const { if (m_addresses.size()) diff --git a/libethereum/LogFilter.h b/libethereum/LogFilter.h index 97ff5a3b1..ff33346f8 100644 --- a/libethereum/LogFilter.h +++ b/libethereum/LogFilter.h @@ -45,15 +45,14 @@ class State; class LogFilter { public: - LogFilter(unsigned _earliest = 0, unsigned _latest = PendingBlock): m_earliest(_earliest), m_latest(_latest) {} + LogFilter(h256 _earliest = EarliestBlockHash, h256 _latest = PendingBlockHash): m_earliest(_earliest), m_latest(_latest) {} void streamRLP(RLPStream& _s) const; h256 sha3() const; - unsigned earliest() const { return m_earliest; } - unsigned latest() const { return m_latest; } + h256 earliest() const { return m_earliest; } + h256 latest() const { return m_latest; } - bool envelops(RelativeBlock _logBlockRelation, u256 _logBlockNumber) const; std::vector bloomPossibilities() const; bool matches(LogBloom _bloom) const; bool matches(State const& _s, unsigned _i) const; @@ -61,16 +60,16 @@ public: LogFilter address(Address _a) { m_addresses.insert(_a); return *this; } LogFilter topic(unsigned _index, h256 const& _t) { if (_index < 4) m_topics[_index].insert(_t); return *this; } - LogFilter withEarliest(int _e) { m_earliest = _e; return *this; } - LogFilter withLatest(int _e) { m_latest = _e; return *this; } + LogFilter withEarliest(h256 _e) { m_earliest = _e; return *this; } + LogFilter withLatest(h256 _e) { m_latest = _e; return *this; } friend std::ostream& dev::eth::operator<<(std::ostream& _out, dev::eth::LogFilter const& _s); private: AddressHash m_addresses; std::array m_topics; - unsigned m_earliest = 0; - unsigned m_latest = LatestBlock; + h256 m_earliest = EarliestBlockHash; + h256 m_latest = PendingBlockHash; }; } diff --git a/libethereum/State.cpp b/libethereum/State.cpp index 1212c2d74..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(&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 { @@ -393,7 +398,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor return ret; } -u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) { #if ETH_TIMED_ENACTMENTS boost::timer t; @@ -404,8 +409,8 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const #endif // Check family: - BlockInfo biParent = _bc.info(_bi.parentHash); - _bi.verifyParent(biParent); + BlockInfo biParent = _bc.info(_block.info.parentHash); + _block.info.verifyParent(biParent); #if ETH_TIMED_ENACTMENTS populateVerify = t.elapsed(); @@ -421,7 +426,7 @@ u256 State::enactOn(bytesConstRef _block, BlockInfo const& _bi, BlockChain const t.restart(); #endif - sync(_bc, _bi.parentHash, BlockInfo(), _ir); + sync(_bc, _block.info.parentHash, BlockInfo(), _ir); resetCurrent(); #if ETH_TIMED_ENACTMENTS @@ -594,6 +599,7 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire for (auto const& tr: rlp[1]) { StandardTrace st; + st.setShowMnemonics(); execute(lh, Transaction(tr.data(), CheckTransaction::Everything), Permanence::Committed, [&](uint64_t _steps, Instruction _inst, bigint _newMemSize, bigint _gasCost, bigint _gas, VM* _vm, ExtVMFace const* _extVM) { st(_steps, _inst, _newMemSize, _gasCost, _gas, _vm, _extVM); }); ret += (ret.empty() ? "[" : ",") + st.json(); @@ -605,15 +611,14 @@ string State::vmTrace(bytesConstRef _block, BlockChain const& _bc, ImportRequire return ret.empty() ? "[]" : (ret + "]"); } -u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirements::value _ir) +u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) { - // m_currentBlock is assumed to be prepopulated and reset. - - BlockInfo bi(_block, (_ir & ImportRequirements::ValidNonce) ? CheckEverything : IgnoreNonce); + DEV_TIMED_FUNCTION_ABOVE(500); + // m_currentBlock is assumed to be prepopulated and reset. #if !ETH_RELEASE - assert(m_previousBlock.hash() == bi.parentHash); - assert(m_currentBlock.parentHash == bi.parentHash); + assert(m_previousBlock.hash() == _block.info.parentHash); + assert(m_currentBlock.parentHash == _block.info.parentHash); assert(rootHash() == m_previousBlock.stateRoot); #endif @@ -622,77 +627,57 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement BOOST_THROW_EXCEPTION(InvalidParentHash()); // Populate m_currentBlock with the correct values. - m_currentBlock = bi; - m_currentBlock.verifyInternals(_block); + m_currentBlock = _block.info; m_currentBlock.noteDirty(); // cnote << "playback begins:" << m_state.root(); // cnote << m_state; - LastHashes lh = _bc.lastHashes((unsigned)m_previousBlock.number); - RLP rlp(_block); + LastHashes lh; + DEV_TIMED_ABOVE(lastHashes, 500) + lh = _bc.lastHashes((unsigned)m_previousBlock.number); + + RLP rlp(_block.block); vector receipts; // All ok with the block generally. Play back the transactions now... unsigned i = 0; - for (auto const& tr: rlp[1]) - { - try + DEV_TIMED_ABOVE(txEcec, 500) + for (auto const& tr: _block.transactions) { - LogOverride o(false); - execute(lh, Transaction(tr.data(), CheckTransaction::Everything)); - } - catch (Exception& ex) - { - badBlock(_block, "Invalid transaction: " + toString(toTransactionException(ex))); - cwarn << " Transaction Index:" << i; - LogOverride o(true); - DEV_IGNORE_EXCEPTIONS(execute(lh, Transaction(tr.data(), CheckTransaction::Everything))); + try + { + LogOverride o(false); + execute(lh, tr); + } + catch (Exception& ex) + { + ex << errinfo_transactionIndex(i); + throw; + } - ex << errinfo_transactionIndex(i); - throw; + RLPStream receiptRLP; + m_receipts.back().streamRLP(receiptRLP); + receipts.push_back(receiptRLP.out()); + ++i; } - RLPStream receiptRLP; - m_receipts.back().streamRLP(receiptRLP); - receipts.push_back(receiptRLP.out()); - ++i; - } + h256 receiptsRoot; + DEV_TIMED_ABOVE(receiptsRoot, 500) + receiptsRoot = orderedTrieRoot(receipts); - auto receiptsRoot = orderedTrieRoot(receipts); if (receiptsRoot != m_currentBlock.receiptsRoot) { - badBlock(_block, "Bad receipts state root"); - cwarn << " Received: " << toString(m_currentBlock.receiptsRoot); - cwarn << " Expected: " << toString(receiptsRoot) << " which is:"; - for (unsigned j = 0; j < i; ++j) - { - auto b = receipts[j]; - cwarn << j << ": "; - cwarn << " RLP: " << RLP(b); - cwarn << " Hex: " << toHex(b); - cwarn << " " << TransactionReceipt(&b); - } - cwarn << " VMTrace:\n" << vmTrace(_block, _bc, _ir); - InvalidReceiptsStateRoot ex; ex << Hash256RequirementError(receiptsRoot, m_currentBlock.receiptsRoot); ex << errinfo_receipts(receipts); - ex << errinfo_vmtrace(vmTrace(_block, _bc, _ir)); + ex << errinfo_vmtrace(vmTrace(_block.block, _bc, _ir)); BOOST_THROW_EXCEPTION(ex); } if (m_currentBlock.logBloom != logBloom()) { - badBlock(_block, "Bad log bloom"); - cwarn << " Receipt blooms:"; - for (unsigned j = 0; j < i; ++j) - { - auto b = receipts[j]; - cwarn << " " << j << ":" << TransactionReceipt(&b).bloom().hex(); - } - cwarn << " Final bloom:" << m_currentBlock.logBloom.hex(); InvalidLogBloom ex; ex << LogBloomRequirementError(logBloom(), m_currentBlock.logBloom); ex << errinfo_receipts(receipts); @@ -705,82 +690,78 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement // Check uncles & apply their rewards to state. if (rlp[2].itemCount() > 2) { - badBlock(_block, "Too many uncles"); - BOOST_THROW_EXCEPTION(TooManyUncles() << errinfo_max(2) << errinfo_got(rlp[2].itemCount())); + TooManyUncles ex; + ex << errinfo_max(2); + ex << errinfo_got(rlp[2].itemCount()); + BOOST_THROW_EXCEPTION(ex); } vector rewarded; - h256Hash excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); + h256Hash excluded; + DEV_TIMED_ABOVE(allKin, 500) + excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); excluded.insert(m_currentBlock.hash()); unsigned ii = 0; - for (auto const& i: rlp[2]) - { - try + DEV_TIMED_ABOVE(uncleCheck, 500) + for (auto const& i: rlp[2]) { - auto h = sha3(i.data()); - if (excluded.count(h)) + try { - badBlock(_block, "Invalid uncle included"); - UncleInChain ex; - ex << errinfo_comment("Uncle in block already mentioned"); - ex << errinfo_unclesExcluded(excluded); - ex << errinfo_hash256(sha3(i.data())); - BOOST_THROW_EXCEPTION(ex); - } - excluded.insert(h); + auto h = sha3(i.data()); + if (excluded.count(h)) + { + UncleInChain ex; + ex << errinfo_comment("Uncle in block already mentioned"); + ex << errinfo_unclesExcluded(excluded); + ex << errinfo_hash256(sha3(i.data())); + BOOST_THROW_EXCEPTION(ex); + } + excluded.insert(h); - BlockInfo uncle; - BlockInfo uncleParent; - uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h); - if (!_bc.isKnown(uncle.parentHash)) - BOOST_THROW_EXCEPTION(UnknownParent()); + BlockInfo uncle = BlockInfo::fromHeader(i.data(), (_ir & ImportRequirements::CheckUncles) ? CheckEverything : IgnoreNonce, h); - uncleParent = BlockInfo(_bc.block(uncle.parentHash)); - if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) - { - badBlock(_block, "Uncle too old"); - cwarn << " Uncle number: " << uncle.number; - cwarn << " Uncle parent number: " << uncleParent.number; - cwarn << " Block number: " << m_currentBlock.number; - UncleTooOld ex; - ex << errinfo_uncleNumber(uncle.number); - ex << errinfo_currentNumber(m_currentBlock.number); - BOOST_THROW_EXCEPTION(ex); + BlockInfo uncleParent; + if (!_bc.isKnown(uncle.parentHash)) + BOOST_THROW_EXCEPTION(UnknownParent()); + uncleParent = BlockInfo(_bc.block(uncle.parentHash)); + + if ((bigint)uncleParent.number < (bigint)m_currentBlock.number - 7) + { + UncleTooOld ex; + ex << errinfo_uncleNumber(uncle.number); + ex << errinfo_currentNumber(m_currentBlock.number); + BOOST_THROW_EXCEPTION(ex); + } + else if (uncle.number == m_currentBlock.number) + { + UncleIsBrother ex; + ex << errinfo_uncleNumber(uncle.number); + ex << errinfo_currentNumber(m_currentBlock.number); + BOOST_THROW_EXCEPTION(ex); + } + uncle.verifyParent(uncleParent); + + rewarded.push_back(uncle); + ++ii; } - else if (uncle.number == m_currentBlock.number) + catch (Exception& ex) { - badBlock(_block, "Uncle is brother"); - cwarn << " Uncle number: " << uncle.number; - cwarn << " Uncle parent number: " << uncleParent.number; - cwarn << " Block number: " << m_currentBlock.number; - UncleIsBrother ex; - ex << errinfo_uncleNumber(uncle.number); - ex << errinfo_currentNumber(m_currentBlock.number); - BOOST_THROW_EXCEPTION(ex); + ex << errinfo_uncleIndex(ii); + throw; } - uncle.verifyParent(uncleParent); - -// tdIncrease += uncle.difficulty; - rewarded.push_back(uncle); - ++ii; } - catch (Exception& ex) - { - ex << errinfo_uncleIndex(ii); - throw; - } - } - applyRewards(rewarded); + DEV_TIMED_ABOVE(applyRewards, 500) + applyRewards(rewarded); // Commit all cached state changes to the state trie. - commit(); + DEV_TIMED_ABOVE(commit, 500) + commit(); // Hash the state trie and check against the state_root hash in m_currentBlock. if (m_currentBlock.stateRoot != m_previousBlock.stateRoot && m_currentBlock.stateRoot != rootHash()) { - badBlock(_block, "Bad state root"); m_db.rollback(); BOOST_THROW_EXCEPTION(InvalidStateRoot() << Hash256RequirementError(rootHash(), m_currentBlock.stateRoot)); } @@ -788,7 +769,6 @@ u256 State::enact(bytesConstRef _block, BlockChain const& _bc, ImportRequirement if (m_currentBlock.gasUsed != gasUsed()) { // Rollback the trie. - badBlock(_block, "Invalid gas used"); m_db.rollback(); BOOST_THROW_EXCEPTION(InvalidGasUsed() << RequirementError(bigint(gasUsed()), bigint(m_currentBlock.gasUsed))); } @@ -803,7 +783,8 @@ void State::cleanup(bool _fullCommit) paranoia("immediately before database commit", true); // Commit the new trie to disk. - clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); + if (isChannelVisible()) // Avoid calling toHex if not needed + clog(StateTrace) << "Committing to disk: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); try { EnforceRefs er(m_db, true); @@ -816,7 +797,8 @@ void State::cleanup(bool _fullCommit) } m_db.commit(); - clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); + if (isChannelVisible()) // Avoid calling toHex if not needed + clog(StateTrace) << "Committed: stateRoot" << m_currentBlock.stateRoot << "=" << rootHash() << "=" << toHex(asBytes(m_db.lookup(rootHash()))); paranoia("immediately after database commit", true); m_previousBlock = m_currentBlock; @@ -866,7 +848,7 @@ bool State::amIJustParanoid(BlockChain const& _bc) cnote << "PARANOIA root:" << s.rootHash(); // s.m_currentBlock.populate(&block.out(), false); // s.m_currentBlock.verifyInternals(&block.out()); - s.enact(&block.out(), _bc, false); // don't check nonce for this since we haven't mined it yet. + s.enact(BlockChain::verifyBlock(block.out()), _bc, false); // don't check nonce for this since we haven't mined it yet. s.cleanup(false); return true; } @@ -1165,6 +1147,8 @@ h256 State::codeHash(Address _contract) const { if (!addressHasCode(_contract)) return EmptySHA3; + if (m_cache[_contract].isFreshCode()) + return sha3(code(_contract)); return m_cache[_contract].codeHash(); } @@ -1203,6 +1187,8 @@ bool State::isTrieGood(bool _enforceRefs, bool _requireNoLeftOvers) const return true; } +#define ETH_VMTIMER 1 + ExecutionResult State::execute(LastHashes const& _lh, Transaction const& _t, Permanence _p, OnOpFunc const& _onOp) { #if ETH_PARANOIA diff --git a/libethereum/State.h b/libethereum/State.h index 9ecab05b5..771cdb6bf 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -64,6 +64,7 @@ using LogBloomRequirementError = boost::tuple const& _uncleBlockHeaders); diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 65c18f4fd..58ecc44fa 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -39,27 +39,6 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, ExecutionResult const& _e return _out; } -std::string badTransaction(bytesConstRef _tx, string const& _err) -{ - stringstream ret; - ret << "========================================================================" << endl; - ret << "== Software Failure " << (_err + string(max(0, 44 - _err.size()), ' ')) << " ==" << endl; - ret << "== Guru Meditation " << sha3(_tx).abridged() << " ==" << endl; - ret << "========================================================================" << endl; - ret << " Transaction: " << toHex(_tx) << endl; - ret << " Transaction RLP: "; - try { - ret << RLP(_tx); - } - catch (Exception& _e) - { - ret << "Invalid: " << _e.what(); - } - ret << endl; - - return ret.str(); -} - TransactionException dev::eth::toTransactionException(Exception const& _e) { // Basic Transaction exceptions diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index fb5566d9a..e9b1cbf80 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -228,8 +228,5 @@ inline std::ostream& operator<<(std::ostream& _out, Transaction const& _t) return _out; } -void badTransaction(bytesConstRef _tx, std::string const& _err); -inline void badTransaction(bytes const& _tx, std::string const& _err) { badTransaction(&_tx, _err); } - } } diff --git a/libethereum/VerifiedBlock.h b/libethereum/VerifiedBlock.h new file mode 100644 index 000000000..ddd808901 --- /dev/null +++ b/libethereum/VerifiedBlock.h @@ -0,0 +1,53 @@ +/* + 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 VerfiedBlock.h + * @author Gav Wood + * @date 2014 + */ + + +#include +#include + +#pragma once + +namespace dev +{ +namespace eth +{ + +class Transaction; + +/// @brief Verified block info, does not hold block data, but a reference instead +struct VerifiedBlockRef +{ + bytesConstRef block; ///< Block data reference + BlockInfo info; ///< Prepopulated block info + std::vector transactions; ///< Verified list of block transactions +}; + +/// @brief Verified block info, combines block data and verified info/transactions +struct VerifiedBlock +{ + VerifiedBlockRef verified; ///< Verified block structures + bytes blockData; ///< Block data +}; + +using VerifiedBlocks = std::vector; + +} +} diff --git a/libevm/ExtVMFace.cpp b/libevm/ExtVMFace.cpp index ebef1fdb0..ad419d2a3 100644 --- a/libevm/ExtVMFace.cpp +++ b/libevm/ExtVMFace.cpp @@ -25,7 +25,7 @@ using namespace std; using namespace dev; using namespace dev::eth; -ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth): +ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, h256 const& _codeHash, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth): myAddress(_myAddress), caller(_caller), origin(_origin), @@ -33,6 +33,7 @@ ExtVMFace::ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 gasPrice(_gasPrice), data(_data), code(_code), + codeHash(_codeHash), lastHashes(_lh), previousBlock(_previousBlock), currentBlock(_currentBlock), diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h index 6b35094bb..357292853 100644 --- a/libevm/ExtVMFace.h +++ b/libevm/ExtVMFace.h @@ -63,10 +63,28 @@ using LogEntries = std::vector; struct LocalisedLogEntry: public LogEntry { LocalisedLogEntry() {} - LocalisedLogEntry(LogEntry const& _le, unsigned _number, h256 _transactionHash = h256()): LogEntry(_le), number(_number), transactionHash(_transactionHash) {} - - unsigned number = 0; - h256 transactionHash; + explicit LocalisedLogEntry(LogEntry const& _le): LogEntry(_le) {}; + + explicit LocalisedLogEntry( + LogEntry const& _le, + h256 _special + ): LogEntry(_le), special(_special) {}; + + explicit LocalisedLogEntry( + LogEntry const& _le, + BlockInfo const& _bi, + h256 _th, + unsigned _ti, + unsigned _li + ): LogEntry(_le), blockHash(_bi.hash()), blockNumber((BlockNumber)_bi.number), transactionHash(_th), transactionIndex(_ti), logIndex(_li), mined(true) {}; + + h256 blockHash = h256(); + BlockNumber blockNumber = 0; + h256 transactionHash = h256(); + unsigned transactionIndex = 0; + unsigned logIndex = 0; + bool mined = false; + h256 special = h256(); }; using LocalisedLogEntries = std::vector; @@ -130,7 +148,7 @@ public: ExtVMFace() = default; /// Full constructor. - ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth); + ExtVMFace(Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes const& _code, h256 const& _codeHash, BlockInfo const& _previousBlock, BlockInfo const& _currentBlock, LastHashes const& _lh, unsigned _depth); virtual ~ExtVMFace() = default; @@ -186,6 +204,7 @@ public: u256 gasPrice; ///< Price of gas (that we already paid). bytesConstRef data; ///< Current input data. bytes code; ///< Current code that is executing. + h256 codeHash; ///< SHA3 hash of the executing code LastHashes lastHashes; ///< Most recent 256 blocks' hashes. BlockInfo previousBlock; ///< The previous block's information. TODO: PoC-8: REMOVE BlockInfo currentBlock; ///< The current block's information. diff --git a/libevm/VMFace.h b/libevm/VMFace.h index cba1c7287..32e645c88 100644 --- a/libevm/VMFace.h +++ b/libevm/VMFace.h @@ -25,14 +25,14 @@ namespace dev namespace eth { -#define ETH_SIMPLE_EXCEPTION_VM(X) struct X: virtual VMException { public X(): VMException(#X) {} }; struct VMException: virtual Exception {}; -struct BreakPointHit: virtual VMException {}; -struct BadInstruction: virtual VMException {}; -struct BadJumpDestination: virtual VMException {}; -struct OutOfGas: virtual VMException {}; -struct OutOfStack: virtual VMException {}; -struct StackUnderflow: virtual VMException {}; +#define ETH_SIMPLE_EXCEPTION_VM(X) struct X: virtual VMException { const char* what() const noexcept override { return #X; } } +ETH_SIMPLE_EXCEPTION_VM(BreakPointHit); +ETH_SIMPLE_EXCEPTION_VM(BadInstruction); +ETH_SIMPLE_EXCEPTION_VM(BadJumpDestination); +ETH_SIMPLE_EXCEPTION_VM(OutOfGas); +ETH_SIMPLE_EXCEPTION_VM(OutOfStack); +ETH_SIMPLE_EXCEPTION_VM(StackUnderflow); /// EVM Virtual Machine interface class VMFace diff --git a/libevmasm/CommonSubexpressionEliminator.cpp b/libevmasm/CommonSubexpressionEliminator.cpp index fadf2776a..8fb4625a8 100644 --- a/libevmasm/CommonSubexpressionEliminator.cpp +++ b/libevmasm/CommonSubexpressionEliminator.cpp @@ -35,6 +35,19 @@ vector CommonSubexpressionEliminator::getOptimizedItems() { optimizeBreakingItem(); + KnownState nextInitialState = m_state; + if (m_breakingItem) + nextInitialState.feedItem(*m_breakingItem); + KnownState nextState = nextInitialState; + + ScopeGuard reset([&]() + { + m_breakingItem = nullptr; + m_storeOperations.clear(); + m_initialState = move(nextInitialState); + m_state = move(nextState); + }); + map initialStackContents; map targetStackContents; int minHeight = m_state.stackHeight() + 1; @@ -52,15 +65,7 @@ vector CommonSubexpressionEliminator::getOptimizedItems() targetStackContents ); if (m_breakingItem) - { items.push_back(*m_breakingItem); - m_state.feedItem(*m_breakingItem); - } - - // cleanup - m_initialState = m_state; - m_breakingItem = nullptr; - m_storeOperations.clear(); return items; } @@ -74,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/libjsqrc/ethereumjs/.jshintrc b/libjsqrc/ethereumjs/.jshintrc index 9502d29bc..a0e8d35eb 100644 --- a/libjsqrc/ethereumjs/.jshintrc +++ b/libjsqrc/ethereumjs/.jshintrc @@ -9,7 +9,7 @@ "maxdepth": 3, "maxerr": 50, /*"maxlen": 80*/ /*this should be our goal*/ - "maxparams": 3, + /*"maxparams": 3,*/ "nonew": true, "unused": true, "undef": true, diff --git a/libjsqrc/ethereumjs/.versions b/libjsqrc/ethereumjs/.versions index ed4a55b6a..f8cf2429e 100644 --- a/libjsqrc/ethereumjs/.versions +++ b/libjsqrc/ethereumjs/.versions @@ -1,4 +1,3 @@ -3stack:bignumber@2.0.0 -ethereum:js@0.0.15-rc12 -meteor@1.1.4 -underscore@1.0.2 +ethereum:web3@0.5.0 +meteor@1.1.6 +underscore@1.0.3 diff --git a/libjsqrc/ethereumjs/bower.json b/libjsqrc/ethereumjs/bower.json index ed620555f..eacbb4509 100644 --- a/libjsqrc/ethereumjs/bower.json +++ b/libjsqrc/ethereumjs/bower.json @@ -1,14 +1,15 @@ { "name": "web3", "namespace": "ethereum", - "version": "0.4.2", + "version": "0.5.0", "description": "Ethereum Compatible JavaScript API", "main": [ "./dist/web3.js", "./dist/web3.min.js" ], "dependencies": { - "bignumber.js": ">=2.0.0" + "bignumber.js": ">=2.0.0", + "crypto-js": "~3.1.4" }, "repository": { "type": "git", diff --git a/libjsqrc/ethereumjs/dist/web3-light.js b/libjsqrc/ethereumjs/dist/web3-light.js deleted file mode 100644 index be6d95eec..000000000 --- a/libjsqrc/ethereumjs/dist/web3-light.js +++ /dev/null @@ -1,3875 +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":6,"./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":6,"./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 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)); -}; - -/** - * 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)); -}; - -module.exports = SolidityParam; - - -},{"../utils/utils":6}],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', - '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 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', - 'mwei': '1000000', - 'babbage': '1000000', - 'gwei': '1000000000', - 'shannon': '1000000000', - 'szabo': '1000000000000', - 'finney': '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: - * - kwei/ada - * - mwei/babbage - * - gwei/shannon - * - szabo - * - finney - * - ether - * - kether/grand/einstein - * - 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: - * - kwei/ada - * - mwei/babbage - * - gwei/shannon - * - szabo - * - finney - * - ether - * - kether/grand/einstein - * - 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; - } -}; - -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 -}; - - -},{"bignumber.js":"bignumber.js"}],7:[function(require,module,exports){ -module.exports={ - "version": "0.4.2" -} - -},{}],8:[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 Method = require('./web3/method'); -var Property = require('./web3/property'); -var Batch = require('./web3/batch'); - -var web3Methods = [ - new Method({ - name: 'sha3', - call: 'web3_sha3', - params: 1 - }) -]; - -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.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 -setupMethods(web3, web3Methods); -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/utils":6,"./version.json":7,"./web3/batch":9,"./web3/db":11,"./web3/eth":13,"./web3/filter":15,"./web3/formatters":16,"./web3/method":20,"./web3/net":21,"./web3/property":22,"./web3/requestmanager":24,"./web3/shh":25,"./web3/watches":26}],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 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":24}],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 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":6,"../web3":8,"./event":14,"./function":17}],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 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":20}],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 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); - } -}; - - -},{}],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 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":6,"./formatters":16,"./method":20,"./property":22}],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 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'); - -/** - * 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 web3.sha3(web3.fromAscii(this._name)).slice(2); -}; - -/** - * 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/utils":6,"../web3":8,"./formatters":16}],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 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":6,"./formatters":16,"./requestmanager":24}],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 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":6}],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 function.js - * @author Marek Kotewicz - * @date 2015 - */ - -var web3 = require('../web3'); -var coder = require('../solidity/coder'); -var utils = require('../utils/utils'); - -/** - * 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 web3.sha3(web3.fromAscii(this._name)).slice(2, 10); -}; - - -SolidityFunction.prototype.unpackOutput = function (output) { - if (output === null) { - 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); - 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); - var callback = this.extractCallback(args); - var payload = this.toPayload(args); - - if (!callback) { - web3.eth.sendTransaction(payload); - return; - } - - web3.eth.sendTransaction(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); - var displayName = this.displayName(); - if (!contract[displayName]) { - contract[displayName] = execute; - } - contract[displayName][this.typeName()] = execute; // circular!!!! -}; - -module.exports = SolidityFunction; - - -},{"../solidity/coder":1,"../utils/utils":6,"../web3":8}],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 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":12,"xmlhttprequest":4}],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 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; - - -},{}],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 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":6,"./errors":12,"./requestmanager":24}],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 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":6,"./property":22}],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 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":24}],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 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; - - -},{}],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 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":6,"./errors":12,"./jsonrpc":19}],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 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":16,"./method":20}],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 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":20}],27:[function(require,module,exports){ - -},{}],"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'); - -// dont override global variable -if (typeof window !== 'undefined' && typeof window.web3 === 'undefined') { - window.web3 = web3; -} - -module.exports = web3; - - -},{"./lib/web3":8,"./lib/web3/contract":10,"./lib/web3/httpprovider":18,"./lib/web3/qtsync":23}]},{},["web3"]) - - -//# sourceMappingURL=web3-light.js.map \ No newline at end of file diff --git a/libjsqrc/ethereumjs/dist/web3-light.js.map b/libjsqrc/ethereumjs/dist/web3-light.js.map deleted file mode 100644 index 53b78067d..000000000 --- a/libjsqrc/ethereumjs/dist/web3-light.js.map +++ /dev/null @@ -1,71 +0,0 @@ -{ - "version": 3, - "sources": [ - "node_modules/browserify/node_modules/browser-pack/_prelude.js", - "lib/solidity/coder.js", - "lib/solidity/formatters.js", - "lib/solidity/param.js", - "lib/utils/browser-xhr.js", - "lib/utils/config.js", - "lib/utils/utils.js", - "lib/version.json", - "lib/web3.js", - "lib/web3/batch.js", - "lib/web3/contract.js", - "lib/web3/db.js", - "lib/web3/errors.js", - "lib/web3/eth.js", - "lib/web3/event.js", - "lib/web3/filter.js", - "lib/web3/formatters.js", - "lib/web3/function.js", - "lib/web3/httpprovider.js", - "lib/web3/jsonrpc.js", - "lib/web3/method.js", - "lib/web3/net.js", - "lib/web3/property.js", - "lib/web3/qtsync.js", - "lib/web3/requestmanager.js", - "lib/web3/shh.js", - "lib/web3/watches.js", - "node_modules/browserify/lib/_empty.js", - "lib/utils/browser-bn.js", - "index.js" - ], - "names": [], - "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1RA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACTA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3dA;AACA;AACA;AACA;;ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9MA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5KA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClHA;;ACAA;AACA;AACA;AACA;AACA;;ACJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", - "file": "generated.js", - "sourceRoot": "", - "sourcesContent": [ - "(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.\n*/\n/** \n * @file coder.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar BigNumber = require('bignumber.js');\nvar utils = require('../utils/utils');\nvar f = require('./formatters');\nvar SolidityParam = require('./param');\n\n/**\n * Should be used to check if a type is an array type\n *\n * @method isArrayType\n * @param {String} type\n * @return {Bool} true is the type is an array, otherwise false\n */\nvar isArrayType = function (type) {\n return type.slice(-2) === '[]';\n};\n\n/**\n * SolidityType prototype is used to encode/decode solidity params of certain type\n */\nvar SolidityType = function (config) {\n this._name = config.name;\n this._match = config.match;\n this._mode = config.mode;\n this._inputFormatter = config.inputFormatter;\n this._outputFormatter = config.outputFormatter;\n};\n\n/**\n * Should be used to determine if this SolidityType do match given type\n *\n * @method isType\n * @param {String} name\n * @return {Bool} true if type match this SolidityType, otherwise false\n */\nSolidityType.prototype.isType = function (name) {\n if (this._match === 'strict') {\n return this._name === name || (name.indexOf(this._name) === 0 && name.slice(this._name.length) === '[]');\n } else if (this._match === 'prefix') {\n // TODO better type detection!\n return name.indexOf(this._name) === 0;\n }\n};\n\n/**\n * Should be used to transform plain param to SolidityParam object\n *\n * @method formatInput\n * @param {Object} param - plain object, or an array of objects\n * @param {Bool} arrayType - true if a param should be encoded as an array\n * @return {SolidityParam} encoded param wrapped in SolidityParam object \n */\nSolidityType.prototype.formatInput = function (param, arrayType) {\n if (utils.isArray(param) && arrayType) { // TODO: should fail if this two are not the same\n var self = this;\n return param.map(function (p) {\n return self._inputFormatter(p);\n }).reduce(function (acc, current) {\n return acc.combine(current);\n }, f.formatInputInt(param.length)).withOffset(32);\n } \n return this._inputFormatter(param);\n};\n\n/**\n * Should be used to transoform SolidityParam to plain param\n *\n * @method formatOutput\n * @param {SolidityParam} byteArray\n * @param {Bool} arrayType - true if a param should be decoded as an array\n * @return {Object} plain decoded param\n */\nSolidityType.prototype.formatOutput = function (param, arrayType) {\n if (arrayType) {\n // let's assume, that we solidity will never return long arrays :P \n var result = [];\n var length = new BigNumber(param.dynamicPart().slice(0, 64), 16);\n for (var i = 0; i < length * 64; i += 64) {\n result.push(this._outputFormatter(new SolidityParam(param.dynamicPart().substr(i + 64, 64))));\n }\n return result;\n }\n return this._outputFormatter(param);\n};\n\n/**\n * Should be used to slice single param from bytes\n *\n * @method sliceParam\n * @param {String} bytes\n * @param {Number} index of param to slice\n * @param {String} type\n * @returns {SolidityParam} param\n */\nSolidityType.prototype.sliceParam = function (bytes, index, type) {\n if (this._mode === 'bytes') {\n return SolidityParam.decodeBytes(bytes, index);\n } else if (isArrayType(type)) {\n return SolidityParam.decodeArray(bytes, index);\n }\n return SolidityParam.decodeParam(bytes, index);\n};\n\n/**\n * SolidityCoder prototype should be used to encode/decode solidity params of any type\n */\nvar SolidityCoder = function (types) {\n this._types = types;\n};\n\n/**\n * This method should be used to transform type to SolidityType\n *\n * @method _requireType\n * @param {String} type\n * @returns {SolidityType} \n * @throws {Error} throws if no matching type is found\n */\nSolidityCoder.prototype._requireType = function (type) {\n var solidityType = this._types.filter(function (t) {\n return t.isType(type);\n })[0];\n\n if (!solidityType) {\n throw Error('invalid solidity type!: ' + type);\n }\n\n return solidityType;\n};\n\n/**\n * Should be used to transform plain param of given type to SolidityParam\n *\n * @method _formatInput\n * @param {String} type of param\n * @param {Object} plain param\n * @return {SolidityParam}\n */\nSolidityCoder.prototype._formatInput = function (type, param) {\n return this._requireType(type).formatInput(param, isArrayType(type));\n};\n\n/**\n * Should be used to encode plain param\n *\n * @method encodeParam\n * @param {String} type\n * @param {Object} plain param\n * @return {String} encoded plain param\n */\nSolidityCoder.prototype.encodeParam = function (type, param) {\n return this._formatInput(type, param).encode();\n};\n\n/**\n * Should be used to encode list of params\n *\n * @method encodeParams\n * @param {Array} types\n * @param {Array} params\n * @return {String} encoded list of params\n */\nSolidityCoder.prototype.encodeParams = function (types, params) {\n var self = this;\n var solidityParams = types.map(function (type, index) {\n return self._formatInput(type, params[index]);\n });\n\n return SolidityParam.encodeList(solidityParams);\n};\n\n/**\n * Should be used to decode bytes to plain param\n *\n * @method decodeParam\n * @param {String} type\n * @param {String} bytes\n * @return {Object} plain param\n */\nSolidityCoder.prototype.decodeParam = function (type, bytes) {\n return this.decodeParams([type], bytes)[0];\n};\n\n/**\n * Should be used to decode list of params\n *\n * @method decodeParam\n * @param {Array} types\n * @param {String} bytes\n * @return {Array} array of plain params\n */\nSolidityCoder.prototype.decodeParams = function (types, bytes) {\n var self = this;\n return types.map(function (type, index) {\n var solidityType = self._requireType(type);\n var p = solidityType.sliceParam(bytes, index, type);\n return solidityType.formatOutput(p, isArrayType(type));\n });\n};\n\nvar coder = new SolidityCoder([\n new SolidityType({\n name: 'address',\n match: 'strict',\n mode: 'value',\n inputFormatter: f.formatInputInt,\n outputFormatter: f.formatOutputAddress\n }),\n new SolidityType({\n name: 'bool',\n match: 'strict',\n mode: 'value',\n inputFormatter: f.formatInputBool,\n outputFormatter: f.formatOutputBool\n }),\n new SolidityType({\n name: 'int',\n match: 'prefix',\n mode: 'value',\n inputFormatter: f.formatInputInt,\n outputFormatter: f.formatOutputInt,\n }),\n new SolidityType({\n name: 'uint',\n match: 'prefix',\n mode: 'value',\n inputFormatter: f.formatInputInt,\n outputFormatter: f.formatOutputUInt\n }),\n new SolidityType({\n name: 'bytes',\n match: 'strict',\n mode: 'bytes',\n inputFormatter: f.formatInputDynamicBytes,\n outputFormatter: f.formatOutputDynamicBytes\n }),\n new SolidityType({\n name: 'bytes',\n match: 'prefix',\n mode: 'value',\n inputFormatter: f.formatInputBytes,\n outputFormatter: f.formatOutputBytes\n }),\n new SolidityType({\n name: 'real',\n match: 'prefix',\n mode: 'value',\n inputFormatter: f.formatInputReal,\n outputFormatter: f.formatOutputReal\n }),\n new SolidityType({\n name: 'ureal',\n match: 'prefix',\n mode: 'value',\n inputFormatter: f.formatInputReal,\n outputFormatter: f.formatOutputUReal\n })\n]);\n\nmodule.exports = coder;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file formatters.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar BigNumber = require('bignumber.js');\nvar utils = require('../utils/utils');\nvar c = require('../utils/config');\nvar SolidityParam = require('./param');\n\n\n/**\n * Formats input value to byte representation of int\n * If value is negative, return it's two's complement\n * If the value is floating point, round it down\n *\n * @method formatInputInt\n * @param {String|Number|BigNumber} value that needs to be formatted\n * @returns {SolidityParam}\n */\nvar formatInputInt = function (value) {\n var padding = c.ETH_PADDING * 2;\n BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE);\n var result = utils.padLeft(utils.toTwosComplement(value).round().toString(16), padding);\n return new SolidityParam(result);\n};\n\n/**\n * Formats input value to byte representation of string\n *\n * @method formatInputBytes\n * @param {String}\n * @returns {SolidityParam}\n */\nvar formatInputBytes = function (value) {\n var result = utils.fromAscii(value, c.ETH_PADDING).substr(2);\n return new SolidityParam(result);\n};\n\n/**\n * Formats input value to byte representation of string\n *\n * @method formatInputDynamicBytes\n * @param {String}\n * @returns {SolidityParam}\n */\nvar formatInputDynamicBytes = function (value) {\n var result = utils.fromAscii(value, c.ETH_PADDING).substr(2);\n return new SolidityParam(formatInputInt(value.length).value + result, 32);\n};\n\n/**\n * Formats input value to byte representation of bool\n *\n * @method formatInputBool\n * @param {Boolean}\n * @returns {SolidityParam}\n */\nvar formatInputBool = function (value) {\n var result = '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0');\n return new SolidityParam(result);\n};\n\n/**\n * Formats input value to byte representation of real\n * Values are multiplied by 2^m and encoded as integers\n *\n * @method formatInputReal\n * @param {String|Number|BigNumber}\n * @returns {SolidityParam}\n */\nvar formatInputReal = function (value) {\n return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128)));\n};\n\n/**\n * Check if input value is negative\n *\n * @method signedIsNegative\n * @param {String} value is hex format\n * @returns {Boolean} true if it is negative, otherwise false\n */\nvar signedIsNegative = function (value) {\n return (new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1';\n};\n\n/**\n * Formats right-aligned output bytes to int\n *\n * @method formatOutputInt\n * @param {SolidityParam} param\n * @returns {BigNumber} right-aligned output bytes formatted to big number\n */\nvar formatOutputInt = function (param) {\n var value = param.staticPart() || \"0\";\n\n // check if it's negative number\n // it it is, return two's complement\n if (signedIsNegative(value)) {\n return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1);\n }\n return new BigNumber(value, 16);\n};\n\n/**\n * Formats right-aligned output bytes to uint\n *\n * @method formatOutputUInt\n * @param {SolidityParam}\n * @returns {BigNumeber} right-aligned output bytes formatted to uint\n */\nvar formatOutputUInt = function (param) {\n var value = param.staticPart() || \"0\";\n return new BigNumber(value, 16);\n};\n\n/**\n * Formats right-aligned output bytes to real\n *\n * @method formatOutputReal\n * @param {SolidityParam}\n * @returns {BigNumber} input bytes formatted to real\n */\nvar formatOutputReal = function (param) {\n return formatOutputInt(param).dividedBy(new BigNumber(2).pow(128)); \n};\n\n/**\n * Formats right-aligned output bytes to ureal\n *\n * @method formatOutputUReal\n * @param {SolidityParam}\n * @returns {BigNumber} input bytes formatted to ureal\n */\nvar formatOutputUReal = function (param) {\n return formatOutputUInt(param).dividedBy(new BigNumber(2).pow(128)); \n};\n\n/**\n * Should be used to format output bool\n *\n * @method formatOutputBool\n * @param {SolidityParam}\n * @returns {Boolean} right-aligned input bytes formatted to bool\n */\nvar formatOutputBool = function (param) {\n return param.staticPart() === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;\n};\n\n/**\n * Should be used to format output string\n *\n * @method formatOutputBytes\n * @param {SolidityParam} left-aligned hex representation of string\n * @returns {String} ascii string\n */\nvar formatOutputBytes = function (param) {\n // length might also be important!\n return utils.toAscii(param.staticPart());\n};\n\n/**\n * Should be used to format output string\n *\n * @method formatOutputDynamicBytes\n * @param {SolidityParam} left-aligned hex representation of string\n * @returns {String} ascii string\n */\nvar formatOutputDynamicBytes = function (param) {\n // length might also be important!\n return utils.toAscii(param.dynamicPart().slice(64));\n};\n\n/**\n * Should be used to format output address\n *\n * @method formatOutputAddress\n * @param {SolidityParam} right-aligned input bytes\n * @returns {String} address\n */\nvar formatOutputAddress = function (param) {\n var value = param.staticPart();\n return \"0x\" + value.slice(value.length - 40, value.length);\n};\n\nmodule.exports = {\n formatInputInt: formatInputInt,\n formatInputBytes: formatInputBytes,\n formatInputDynamicBytes: formatInputDynamicBytes,\n formatInputBool: formatInputBool,\n formatInputReal: formatInputReal,\n formatOutputInt: formatOutputInt,\n formatOutputUInt: formatOutputUInt,\n formatOutputReal: formatOutputReal,\n formatOutputUReal: formatOutputUReal,\n formatOutputBool: formatOutputBool,\n formatOutputBytes: formatOutputBytes,\n formatOutputDynamicBytes: formatOutputDynamicBytes,\n formatOutputAddress: formatOutputAddress\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file param.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar utils = require('../utils/utils');\n\n/**\n * SolidityParam object prototype.\n * Should be used when encoding, decoding solidity bytes\n */\nvar SolidityParam = function (value, offset) {\n this.value = value || '';\n this.offset = offset; // offset in bytes\n};\n\n/**\n * This method should be used to get length of params's dynamic part\n * \n * @method dynamicPartLength\n * @returns {Number} length of dynamic part (in bytes)\n */\nSolidityParam.prototype.dynamicPartLength = function () {\n return this.dynamicPart().length / 2;\n};\n\n/**\n * This method should be used to create copy of solidity param with different offset\n *\n * @method withOffset\n * @param {Number} offset length in bytes\n * @returns {SolidityParam} new solidity param with applied offset\n */\nSolidityParam.prototype.withOffset = function (offset) {\n return new SolidityParam(this.value, offset);\n};\n\n/**\n * This method should be used to combine solidity params together\n * eg. when appending an array\n *\n * @method combine\n * @param {SolidityParam} param with which we should combine\n * @param {SolidityParam} result of combination\n */\nSolidityParam.prototype.combine = function (param) {\n return new SolidityParam(this.value + param.value); \n};\n\n/**\n * This method should be called to check if param has dynamic size.\n * If it has, it returns true, otherwise false\n *\n * @method isDynamic\n * @returns {Boolean}\n */\nSolidityParam.prototype.isDynamic = function () {\n return this.value.length > 64;\n};\n\n/**\n * This method should be called to transform offset to bytes\n *\n * @method offsetAsBytes\n * @returns {String} bytes representation of offset\n */\nSolidityParam.prototype.offsetAsBytes = function () {\n return !this.isDynamic() ? '' : utils.padLeft(utils.toTwosComplement(this.offset).toString(16), 64);\n};\n\n/**\n * This method should be called to get static part of param\n *\n * @method staticPart\n * @returns {String} offset if it is a dynamic param, otherwise value\n */\nSolidityParam.prototype.staticPart = function () {\n if (!this.isDynamic()) {\n return this.value; \n } \n return this.offsetAsBytes();\n};\n\n/**\n * This method should be called to get dynamic part of param\n *\n * @method dynamicPart\n * @returns {String} returns a value if it is a dynamic param, otherwise empty string\n */\nSolidityParam.prototype.dynamicPart = function () {\n return this.isDynamic() ? this.value : '';\n};\n\n/**\n * This method should be called to encode param\n *\n * @method encode\n * @returns {String}\n */\nSolidityParam.prototype.encode = function () {\n return this.staticPart() + this.dynamicPart();\n};\n\n/**\n * This method should be called to encode array of params\n *\n * @method encodeList\n * @param {Array[SolidityParam]} params\n * @returns {String}\n */\nSolidityParam.encodeList = function (params) {\n \n // updating offsets\n var totalOffset = params.length * 32;\n var offsetParams = params.map(function (param) {\n if (!param.isDynamic()) {\n return param;\n }\n var offset = totalOffset;\n totalOffset += param.dynamicPartLength();\n return param.withOffset(offset);\n });\n\n // encode everything!\n return offsetParams.reduce(function (result, param) {\n return result + param.dynamicPart();\n }, offsetParams.reduce(function (result, param) {\n return result + param.staticPart();\n }, ''));\n};\n\n/**\n * This method should be used to decode plain (static) solidity param at given index\n *\n * @method decodeParam\n * @param {String} bytes\n * @param {Number} index\n * @returns {SolidityParam}\n */\nSolidityParam.decodeParam = function (bytes, index) {\n index = index || 0;\n return new SolidityParam(bytes.substr(index * 64, 64)); \n};\n\n/**\n * This method should be called to get offset value from bytes at given index\n *\n * @method getOffset\n * @param {String} bytes\n * @param {Number} index\n * @returns {Number} offset as number\n */\nvar getOffset = function (bytes, index) {\n // we can do this cause offset is rather small\n return parseInt('0x' + bytes.substr(index * 64, 64));\n};\n\n/**\n * This method should be called to decode solidity bytes param at given index\n *\n * @method decodeBytes\n * @param {String} bytes\n * @param {Number} index\n * @returns {SolidityParam}\n */\nSolidityParam.decodeBytes = function (bytes, index) {\n index = index || 0;\n //TODO add support for strings longer than 32 bytes\n //var length = parseInt('0x' + bytes.substr(offset * 64, 64));\n\n var offset = getOffset(bytes, index);\n\n // 2 * , cause we also parse length\n return new SolidityParam(bytes.substr(offset * 2, 2 * 64));\n};\n\n/**\n * This method should be used to decode solidity array at given index\n *\n * @method decodeArray\n * @param {String} bytes\n * @param {Number} index\n * @returns {SolidityParam}\n */\nSolidityParam.decodeArray = function (bytes, index) {\n index = index || 0;\n var offset = getOffset(bytes, index);\n var length = parseInt('0x' + bytes.substr(offset * 2, 64));\n return new SolidityParam(bytes.substr(offset * 2, (length + 1) * 64));\n};\n\nmodule.exports = SolidityParam;\n\n", - "'use strict';\n\n// go env doesn't have and need XMLHttpRequest\nif (typeof XMLHttpRequest === 'undefined') {\n exports.XMLHttpRequest = {};\n} else {\n exports.XMLHttpRequest = XMLHttpRequest; // jshint ignore:line\n}\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file config.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/**\n * Utils\n * \n * @module utils\n */\n\n/**\n * Utility functions\n * \n * @class [utils] config\n * @constructor\n */\n\n/// required to define ETH_BIGNUMBER_ROUNDING_MODE\nvar BigNumber = require('bignumber.js');\n\nvar ETH_UNITS = [ \n 'wei', \n 'Kwei', \n 'Mwei', \n 'Gwei', \n 'szabo', \n 'finney', \n 'ether', \n 'grand', \n 'Mether', \n 'Gether', \n 'Tether', \n 'Pether', \n 'Eether', \n 'Zether', \n 'Yether', \n 'Nether', \n 'Dether', \n 'Vether', \n 'Uether' \n];\n\nmodule.exports = {\n ETH_PADDING: 32,\n ETH_SIGNATURE_LENGTH: 4,\n ETH_UNITS: ETH_UNITS,\n ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN },\n ETH_POLLING_TIMEOUT: 1000,\n defaultBlock: 'latest',\n defaultAccount: undefined\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file utils.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\n/**\n * Utils\n * \n * @module utils\n */\n\n/**\n * Utility functions\n * \n * @class [utils] utils\n * @constructor\n */\n\nvar BigNumber = require('bignumber.js');\n\nvar unitMap = {\n 'wei': '1',\n 'kwei': '1000',\n 'ada': '1000',\n 'mwei': '1000000',\n 'babbage': '1000000',\n 'gwei': '1000000000',\n 'shannon': '1000000000',\n 'szabo': '1000000000000',\n 'finney': '1000000000000000',\n 'ether': '1000000000000000000',\n 'kether': '1000000000000000000000',\n 'grand': '1000000000000000000000',\n 'einstein': '1000000000000000000000',\n 'mether': '1000000000000000000000000',\n 'gether': '1000000000000000000000000000',\n 'tether': '1000000000000000000000000000000'\n};\n\n/**\n * Should be called to pad string to expected length\n *\n * @method padLeft\n * @param {String} string to be padded\n * @param {Number} characters that result string should have\n * @param {String} sign, by default 0\n * @returns {String} right aligned string\n */\nvar padLeft = function (string, chars, sign) {\n return new Array(chars - string.length + 1).join(sign ? sign : \"0\") + string;\n};\n\n/** \n * Should be called to get sting from it's hex representation\n *\n * @method toAscii\n * @param {String} string in hex\n * @returns {String} ascii string representation of hex value\n */\nvar toAscii = function(hex) {\n// Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x') {\n i = 2;\n }\n for (; i < l; i+=2) {\n var code = parseInt(hex.substr(i, 2), 16);\n if (code === 0) {\n break;\n }\n\n str += String.fromCharCode(code);\n }\n\n return str;\n};\n \n/**\n * Shold be called to get hex representation (prefixed by 0x) of ascii string \n *\n * @method toHexNative\n * @param {String} string\n * @returns {String} hex representation of input string\n */\nvar toHexNative = function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n};\n\n/**\n * Shold be called to get hex representation (prefixed by 0x) of ascii string \n *\n * @method fromAscii\n * @param {String} string\n * @param {Number} optional padding\n * @returns {String} hex representation of input string\n */\nvar fromAscii = function(str, pad) {\n pad = pad === undefined ? 0 : pad;\n var hex = toHexNative(str);\n while (hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n};\n\n/**\n * Should be used to create full function/event name from json abi\n *\n * @method transformToFullName\n * @param {Object} json-abi\n * @return {String} full fnction/event name\n */\nvar transformToFullName = function (json) {\n if (json.name.indexOf('(') !== -1) {\n return json.name;\n }\n\n var typeName = json.inputs.map(function(i){return i.type; }).join();\n return json.name + '(' + typeName + ')';\n};\n\n/**\n * Should be called to get display name of contract function\n * \n * @method extractDisplayName\n * @param {String} name of function/event\n * @returns {String} display name for function/event eg. multiply(uint256) -> multiply\n */\nvar extractDisplayName = function (name) {\n var length = name.indexOf('('); \n return length !== -1 ? name.substr(0, length) : name;\n};\n\n/// @returns overloaded part of function/event name\nvar extractTypeName = function (name) {\n /// TODO: make it invulnerable\n var length = name.indexOf('(');\n return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : \"\";\n};\n\n/**\n * Converts value to it's decimal representation in string\n *\n * @method toDecimal\n * @param {String|Number|BigNumber}\n * @return {String}\n */\nvar toDecimal = function (value) {\n return toBigNumber(value).toNumber();\n};\n\n/**\n * Converts value to it's hex representation\n *\n * @method fromDecimal\n * @param {String|Number|BigNumber}\n * @return {String}\n */\nvar fromDecimal = function (value) {\n var number = toBigNumber(value);\n var result = number.toString(16);\n\n return number.lessThan(0) ? '-0x' + result.substr(1) : '0x' + result;\n};\n\n/**\n * Auto converts any given value into it's hex representation.\n *\n * And even stringifys objects before.\n *\n * @method toHex\n * @param {String|Number|BigNumber|Object}\n * @return {String}\n */\nvar toHex = function (val) {\n /*jshint maxcomplexity:7 */\n\n if (isBoolean(val))\n return fromDecimal(+val);\n\n if (isBigNumber(val))\n return fromDecimal(val);\n\n if (isObject(val))\n return fromAscii(JSON.stringify(val));\n\n // if its a negative number, pass it through fromDecimal\n if (isString(val)) {\n if (val.indexOf('-0x') === 0)\n return fromDecimal(val);\n else if (!isFinite(val))\n return fromAscii(val);\n }\n\n return fromDecimal(val);\n};\n\n/**\n * Returns value of unit in Wei\n *\n * @method getValueOfUnit\n * @param {String} unit the unit to convert to, default ether\n * @returns {BigNumber} value of the unit (in Wei)\n * @throws error if the unit is not correct:w\n */\nvar getValueOfUnit = function (unit) {\n unit = unit ? unit.toLowerCase() : 'ether';\n var unitValue = unitMap[unit];\n if (unitValue === undefined) {\n throw new Error('This unit doesn\\'t exists, please use the one of the following units' + JSON.stringify(unitMap, null, 2));\n }\n return new BigNumber(unitValue, 10);\n};\n\n/**\n * Takes a number of wei and converts it to any other ether unit.\n *\n * Possible units are:\n * - kwei/ada\n * - mwei/babbage\n * - gwei/shannon\n * - szabo\n * - finney\n * - ether\n * - kether/grand/einstein\n * - mether\n * - gether\n * - tether\n *\n * @method fromWei\n * @param {Number|String} number can be a number, number string or a HEX of a decimal\n * @param {String} unit the unit to convert to, default ether\n * @return {String|Object} When given a BigNumber object it returns one as well, otherwise a number\n*/\nvar fromWei = function(number, unit) {\n var returnValue = toBigNumber(number).dividedBy(getValueOfUnit(unit));\n\n return isBigNumber(number) ? returnValue : returnValue.toString(10); \n};\n\n/**\n * Takes a number of a unit and converts it to wei.\n *\n * Possible units are:\n * - kwei/ada\n * - mwei/babbage\n * - gwei/shannon\n * - szabo\n * - finney\n * - ether\n * - kether/grand/einstein\n * - mether\n * - gether\n * - tether\n *\n * @method toWei\n * @param {Number|String|BigNumber} number can be a number, number string or a HEX of a decimal\n * @param {String} unit the unit to convert from, default ether\n * @return {String|Object} When given a BigNumber object it returns one as well, otherwise a number\n*/\nvar toWei = function(number, unit) {\n var returnValue = toBigNumber(number).times(getValueOfUnit(unit));\n\n return isBigNumber(number) ? returnValue : returnValue.toString(10); \n};\n\n/**\n * Takes an input and transforms it into an bignumber\n *\n * @method toBigNumber\n * @param {Number|String|BigNumber} a number, string, HEX string or BigNumber\n * @return {BigNumber} BigNumber\n*/\nvar toBigNumber = function(number) {\n /*jshint maxcomplexity:5 */\n number = number || 0;\n if (isBigNumber(number))\n return number;\n\n if (isString(number) && (number.indexOf('0x') === 0 || number.indexOf('-0x') === 0)) {\n return new BigNumber(number.replace('0x',''), 16);\n }\n \n return new BigNumber(number.toString(10), 10);\n};\n\n/**\n * Takes and input transforms it into bignumber and if it is negative value, into two's complement\n *\n * @method toTwosComplement\n * @param {Number|String|BigNumber}\n * @return {BigNumber}\n */\nvar toTwosComplement = function (number) {\n var bigNumber = toBigNumber(number);\n if (bigNumber.lessThan(0)) {\n return new BigNumber(\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\", 16).plus(bigNumber).plus(1);\n }\n return bigNumber;\n};\n\n/**\n * Checks if the given string is strictly an address\n *\n * @method isStrictAddress\n * @param {String} address the given HEX adress\n * @return {Boolean}\n*/\nvar isStrictAddress = function (address) {\n return /^0x[0-9a-f]{40}$/.test(address);\n};\n\n/**\n * Checks if the given string is an address\n *\n * @method isAddress\n * @param {String} address the given HEX adress\n * @return {Boolean}\n*/\nvar isAddress = function (address) {\n return /^(0x)?[0-9a-f]{40}$/.test(address);\n};\n\n/**\n * Transforms given string to valid 20 bytes-length addres with 0x prefix\n *\n * @method toAddress\n * @param {String} address\n * @return {String} formatted address\n */\nvar toAddress = function (address) {\n if (isStrictAddress(address)) {\n return address;\n }\n \n if (/^[0-9a-f]{40}$/.test(address)) {\n return '0x' + address;\n }\n\n return '0x' + padLeft(toHex(address).substr(2), 40);\n};\n\n\n/**\n * Returns true if object is BigNumber, otherwise false\n *\n * @method isBigNumber\n * @param {Object}\n * @return {Boolean} \n */\nvar isBigNumber = function (object) {\n return object instanceof BigNumber ||\n (object && object.constructor && object.constructor.name === 'BigNumber');\n};\n\n/**\n * Returns true if object is string, otherwise false\n * \n * @method isString\n * @param {Object}\n * @return {Boolean}\n */\nvar isString = function (object) {\n return typeof object === 'string' ||\n (object && object.constructor && object.constructor.name === 'String');\n};\n\n/**\n * Returns true if object is function, otherwise false\n *\n * @method isFunction\n * @param {Object}\n * @return {Boolean}\n */\nvar isFunction = function (object) {\n return typeof object === 'function';\n};\n\n/**\n * Returns true if object is Objet, otherwise false\n *\n * @method isObject\n * @param {Object}\n * @return {Boolean}\n */\nvar isObject = function (object) {\n return typeof object === 'object';\n};\n\n/**\n * Returns true if object is boolean, otherwise false\n *\n * @method isBoolean\n * @param {Object}\n * @return {Boolean}\n */\nvar isBoolean = function (object) {\n return typeof object === 'boolean';\n};\n\n/**\n * Returns true if object is array, otherwise false\n *\n * @method isArray\n * @param {Object}\n * @return {Boolean}\n */\nvar isArray = function (object) {\n return object instanceof Array; \n};\n\n/**\n * Returns true if given string is valid json object\n * \n * @method isJson\n * @param {String}\n * @return {Boolean}\n */\nvar isJson = function (str) {\n try {\n return !!JSON.parse(str);\n } catch (e) {\n return false;\n }\n};\n\nmodule.exports = {\n padLeft: padLeft,\n toHex: toHex,\n toDecimal: toDecimal,\n fromDecimal: fromDecimal,\n toAscii: toAscii,\n fromAscii: fromAscii,\n transformToFullName: transformToFullName,\n extractDisplayName: extractDisplayName,\n extractTypeName: extractTypeName,\n toWei: toWei,\n fromWei: fromWei,\n toBigNumber: toBigNumber,\n toTwosComplement: toTwosComplement,\n toAddress: toAddress,\n isBigNumber: isBigNumber,\n isStrictAddress: isStrictAddress,\n isAddress: isAddress,\n isFunction: isFunction,\n isString: isString,\n isObject: isObject,\n isBoolean: isBoolean,\n isArray: isArray,\n isJson: isJson\n};\n\n", - "module.exports={\n \"version\": \"0.4.2\"\n}\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file web3.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Fabian Vogelsteller \n * Gav Wood \n * @date 2014\n */\n\nvar version = require('./version.json');\nvar net = require('./web3/net');\nvar eth = require('./web3/eth');\nvar db = require('./web3/db');\nvar shh = require('./web3/shh');\nvar watches = require('./web3/watches');\nvar Filter = require('./web3/filter');\nvar utils = require('./utils/utils');\nvar formatters = require('./web3/formatters');\nvar RequestManager = require('./web3/requestmanager');\nvar c = require('./utils/config');\nvar Method = require('./web3/method');\nvar Property = require('./web3/property');\nvar Batch = require('./web3/batch');\n\nvar web3Methods = [\n new Method({\n name: 'sha3',\n call: 'web3_sha3',\n params: 1\n })\n];\n\nvar web3Properties = [\n new Property({\n name: 'version.client',\n getter: 'web3_clientVersion'\n }),\n new Property({\n name: 'version.network',\n getter: 'net_version',\n inputFormatter: utils.toDecimal\n }),\n new Property({\n name: 'version.ethereum',\n getter: 'eth_protocolVersion',\n inputFormatter: utils.toDecimal\n }),\n new Property({\n name: 'version.whisper',\n getter: 'shh_version',\n inputFormatter: utils.toDecimal\n })\n];\n\n/// creates methods in a given object based on method description on input\n/// setups api calls for these methods\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n method.attachToObject(obj);\n });\n};\n\n/// creates properties in a given object based on properties description on input\n/// setups api calls for these properties\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n property.attachToObject(obj);\n });\n};\n\n/// setups web3 object, and it's in-browser executed methods\nvar web3 = {};\nweb3.providers = {};\nweb3.version = {};\nweb3.version.api = version.version;\nweb3.eth = {};\n\n/*jshint maxparams:4 */\nweb3.eth.filter = function (fil, eventParams, options, formatter) {\n\n // if its event, treat it differently\n // TODO: simplify and remove\n if (fil._isEvent) {\n return fil(eventParams, options);\n }\n\n // what outputLogFormatter? that's wrong\n //return new Filter(fil, watches.eth(), formatters.outputLogFormatter);\n return new Filter(fil, watches.eth(), formatter || formatters.outputLogFormatter);\n};\n/*jshint maxparams:3 */\n\nweb3.shh = {};\nweb3.shh.filter = function (fil) {\n return new Filter(fil, watches.shh(), formatters.outputPostFormatter);\n};\nweb3.net = {};\nweb3.db = {};\nweb3.setProvider = function (provider) {\n RequestManager.getInstance().setProvider(provider);\n};\nweb3.reset = function () {\n RequestManager.getInstance().reset();\n c.defaultBlock = 'latest';\n c.defaultAccount = undefined;\n};\nweb3.toHex = utils.toHex;\nweb3.toAscii = utils.toAscii;\nweb3.fromAscii = utils.fromAscii;\nweb3.toDecimal = utils.toDecimal;\nweb3.fromDecimal = utils.fromDecimal;\nweb3.toBigNumber = utils.toBigNumber;\nweb3.toWei = utils.toWei;\nweb3.fromWei = utils.fromWei;\nweb3.isAddress = utils.isAddress;\nweb3.createBatch = function () {\n return new Batch();\n};\n\n// ADD defaultblock\nObject.defineProperty(web3.eth, 'defaultBlock', {\n get: function () {\n return c.defaultBlock;\n },\n set: function (val) {\n c.defaultBlock = val;\n return val;\n }\n});\n\nObject.defineProperty(web3.eth, 'defaultAccount', {\n get: function () {\n return c.defaultAccount;\n },\n set: function (val) {\n c.defaultAccount = val;\n return val;\n }\n});\n\n/// setups all api methods\nsetupMethods(web3, web3Methods);\nsetupProperties(web3, web3Properties);\nsetupMethods(web3.net, net.methods);\nsetupProperties(web3.net, net.properties);\nsetupMethods(web3.eth, eth.methods);\nsetupProperties(web3.eth, eth.properties);\nsetupMethods(web3.db, db.methods);\nsetupMethods(web3.shh, shh.methods);\n\nmodule.exports = web3;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file batch.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar RequestManager = require('./requestmanager');\n\nvar Batch = function () {\n this.requests = [];\n};\n\n/**\n * Should be called to add create new request to batch request\n *\n * @method add\n * @param {Object} jsonrpc requet object\n */\nBatch.prototype.add = function (request) {\n this.requests.push(request);\n};\n\n/**\n * Should be called to execute batch request\n *\n * @method execute\n */\nBatch.prototype.execute = function () {\n var requests = this.requests;\n RequestManager.getInstance().sendBatch(requests, function (err, results) {\n results = results || [];\n requests.map(function (request, index) {\n return results[index] || {};\n }).map(function (result, index) {\n return requests[index].format ? requests[index].format(result.result) : result.result;\n }).forEach(function (result, index) {\n if (requests[index].callback) {\n requests[index].callback(err, result);\n }\n });\n }); \n};\n\nmodule.exports = Batch;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file contract.js\n * @author Marek Kotewicz \n * @date 2014\n */\n\nvar web3 = require('../web3'); \nvar utils = require('../utils/utils');\nvar coder = require('../solidity/coder');\nvar SolidityEvent = require('./event');\nvar SolidityFunction = require('./function');\n\n/**\n * Should be called to encode constructor params\n *\n * @method encodeConstructorParams\n * @param {Array} abi\n * @param {Array} constructor params\n */\nvar encodeConstructorParams = function (abi, params) {\n return abi.filter(function (json) {\n return json.type === 'constructor' && json.inputs.length === params.length;\n }).map(function (json) {\n return json.inputs.map(function (input) {\n return input.type;\n });\n }).map(function (types) {\n return coder.encodeParams(types, params);\n })[0] || '';\n};\n\n/**\n * Should be called to add functions to contract object\n *\n * @method addFunctionsToContract\n * @param {Contract} contract\n * @param {Array} abi\n */\nvar addFunctionsToContract = function (contract, abi) {\n abi.filter(function (json) {\n return json.type === 'function';\n }).map(function (json) {\n return new SolidityFunction(json, contract.address);\n }).forEach(function (f) {\n f.attachToContract(contract);\n });\n};\n\n/**\n * Should be called to add events to contract object\n *\n * @method addEventsToContract\n * @param {Contract} contract\n * @param {Array} abi\n */\nvar addEventsToContract = function (contract, abi) {\n abi.filter(function (json) {\n return json.type === 'event';\n }).map(function (json) {\n return new SolidityEvent(json, contract.address);\n }).forEach(function (e) {\n e.attachToContract(contract);\n });\n};\n\n/**\n * Should be called to create new ContractFactory\n *\n * @method contract\n * @param {Array} abi\n * @returns {ContractFactory} new contract factory\n */\nvar contract = function (abi) {\n return new ContractFactory(abi);\n};\n\n/**\n * Should be called to create new ContractFactory instance\n *\n * @method ContractFactory\n * @param {Array} abi\n */\nvar ContractFactory = function (abi) {\n this.abi = abi;\n};\n\n/**\n * Should be called to create new contract on a blockchain\n * \n * @method new\n * @param {Any} contract constructor param1 (optional)\n * @param {Any} contract constructor param2 (optional)\n * @param {Object} contract transaction object (required)\n * @param {Function} callback\n * @returns {Contract} returns contract if no callback was passed,\n * otherwise calls callback function (err, contract)\n */\nContractFactory.prototype.new = function () {\n // parse arguments\n var options = {}; // required!\n var callback;\n\n var args = Array.prototype.slice.call(arguments);\n if (utils.isFunction(args[args.length - 1])) {\n callback = args.pop();\n }\n\n var last = args[args.length - 1];\n if (utils.isObject(last) && !utils.isArray(last)) {\n options = args.pop();\n }\n\n // throw an error if there are no options\n\n var bytes = encodeConstructorParams(this.abi, args);\n options.data += bytes;\n\n if (!callback) {\n var address = web3.eth.sendTransaction(options);\n return this.at(address);\n }\n \n var self = this;\n web3.eth.sendTransaction(options, function (err, address) {\n if (err) {\n callback(err);\n }\n self.at(address, callback); \n }); \n};\n\n/**\n * Should be called to get access to existing contract on a blockchain\n *\n * @method at\n * @param {Address} contract address (required)\n * @param {Function} callback {optional)\n * @returns {Contract} returns contract if no callback was passed,\n * otherwise calls callback function (err, contract)\n */\nContractFactory.prototype.at = function (address, callback) {\n // TODO: address is required\n \n if (callback) {\n callback(null, new Contract(this.abi, address));\n } \n return new Contract(this.abi, address);\n};\n\n/**\n * Should be called to create new contract instance\n *\n * @method Contract\n * @param {Array} abi\n * @param {Address} contract address\n */\nvar Contract = function (abi, address) {\n this.address = address;\n addFunctionsToContract(this, abi);\n addEventsToContract(this, abi);\n};\n\nmodule.exports = contract;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file db.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar Method = require('./method');\n\nvar putString = new Method({\n name: 'putString',\n call: 'db_putString',\n params: 3\n});\n\n\nvar getString = new Method({\n name: 'getString',\n call: 'db_getString',\n params: 2\n});\n\nvar putHex = new Method({\n name: 'putHex',\n call: 'db_putHex',\n params: 3\n});\n\nvar getHex = new Method({\n name: 'getHex',\n call: 'db_getHex',\n params: 2\n});\n\nvar methods = [\n putString, getString, putHex, getHex\n];\n\nmodule.exports = {\n methods: methods\n};\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file errors.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nmodule.exports = {\n InvalidNumberOfParams: function () {\n return new Error('Invalid number of input parameters');\n },\n InvalidConnection: function (host){\n return new Error('CONNECTION ERROR: Couldn\\'t connect to node '+ host +', is it running?');\n },\n InvalidProvider: function () {\n return new Error('Providor not set or invalid');\n },\n InvalidResponse: function (result){\n var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response';\n return new Error(message);\n }\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file eth.js\n * @author Marek Kotewicz \n * @author Fabian Vogelsteller \n * @date 2015\n */\n\n/**\n * Web3\n *\n * @module web3\n */\n\n/**\n * Eth methods and properties\n *\n * An example method object can look as follows:\n *\n * {\n * name: 'getBlock',\n * call: blockCall,\n * params: 2,\n * outputFormatter: formatters.outputBlockFormatter,\n * inputFormatter: [ // can be a formatter funciton or an array of functions. Where each item in the array will be used for one parameter\n * utils.toHex, // formats paramter 1\n * function(param){ return !!param; } // formats paramter 2\n * ]\n * },\n *\n * @class [web3] eth\n * @constructor\n */\n\n\"use strict\";\n\nvar formatters = require('./formatters');\nvar utils = require('../utils/utils');\nvar Method = require('./method');\nvar Property = require('./property');\n\nvar blockCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? \"eth_getBlockByHash\" : \"eth_getBlockByNumber\";\n};\n\nvar transactionFromBlockCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getTransactionByBlockHashAndIndex' : 'eth_getTransactionByBlockNumberAndIndex';\n};\n\nvar uncleCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleByBlockHashAndIndex' : 'eth_getUncleByBlockNumberAndIndex';\n};\n\nvar getBlockTransactionCountCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getBlockTransactionCountByHash' : 'eth_getBlockTransactionCountByNumber';\n};\n\nvar uncleCountCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleCountByBlockHash' : 'eth_getUncleCountByBlockNumber';\n};\n\n/// @returns an array of objects describing web3.eth api methods\n\nvar getBalance = new Method({\n name: 'getBalance',\n call: 'eth_getBalance',\n params: 2,\n inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter],\n outputFormatter: formatters.outputBigNumberFormatter\n});\n\nvar getStorageAt = new Method({\n name: 'getStorageAt',\n call: 'eth_getStorageAt',\n params: 3,\n inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar getCode = new Method({\n name: 'getCode',\n call: 'eth_getCode',\n params: 2,\n inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar getBlock = new Method({\n name: 'getBlock',\n call: blockCall,\n params: 2,\n inputFormatter: [formatters.inputBlockNumberFormatter, function (val) { return !!val; }],\n outputFormatter: formatters.outputBlockFormatter\n});\n\nvar getUncle = new Method({\n name: 'getUncle',\n call: uncleCall,\n params: 2,\n inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex],\n outputFormatter: formatters.outputBlockFormatter,\n\n});\n\nvar getCompilers = new Method({\n name: 'getCompilers',\n call: 'eth_getCompilers',\n params: 0\n});\n\nvar getBlockTransactionCount = new Method({\n name: 'getBlockTransactionCount',\n call: getBlockTransactionCountCall,\n params: 1,\n inputFormatter: [formatters.inputBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar getBlockUncleCount = new Method({\n name: 'getBlockUncleCount',\n call: uncleCountCall,\n params: 1,\n inputFormatter: [formatters.inputBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar getTransaction = new Method({\n name: 'getTransaction',\n call: 'eth_getTransactionByHash',\n params: 1,\n outputFormatter: formatters.outputTransactionFormatter\n});\n\nvar getTransactionFromBlock = new Method({\n name: 'getTransactionFromBlock',\n call: transactionFromBlockCall,\n params: 2,\n inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex],\n outputFormatter: formatters.outputTransactionFormatter\n});\n\nvar getTransactionCount = new Method({\n name: 'getTransactionCount',\n call: 'eth_getTransactionCount',\n params: 2,\n inputFormatter: [null, formatters.inputDefaultBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar sendTransaction = new Method({\n name: 'sendTransaction',\n call: 'eth_sendTransaction',\n params: 1,\n inputFormatter: [formatters.inputTransactionFormatter]\n});\n\nvar call = new Method({\n name: 'call',\n call: 'eth_call',\n params: 2,\n inputFormatter: [formatters.inputTransactionFormatter, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar estimateGas = new Method({\n name: 'estimateGas',\n call: 'eth_estimateGas',\n params: 1,\n inputFormatter: [formatters.inputTransactionFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar compileSolidity = new Method({\n name: 'compile.solidity',\n call: 'eth_compileSolidity',\n params: 1\n});\n\nvar compileLLL = new Method({\n name: 'compile.lll',\n call: 'eth_compileLLL',\n params: 1\n});\n\nvar compileSerpent = new Method({\n name: 'compile.serpent',\n call: 'eth_compileSerpent',\n params: 1\n});\n\nvar submitWork = new Method({\n name: 'submitWork',\n call: 'eth_submitWork',\n params: 3\n});\n\nvar getWork = new Method({\n name: 'getWork',\n call: 'eth_getWork',\n params: 0\n});\n\nvar methods = [\n getBalance,\n getStorageAt,\n getCode,\n getBlock,\n getUncle,\n getCompilers,\n getBlockTransactionCount,\n getBlockUncleCount,\n getTransaction,\n getTransactionFromBlock,\n getTransactionCount,\n call,\n estimateGas,\n sendTransaction,\n compileSolidity,\n compileLLL,\n compileSerpent,\n submitWork,\n getWork\n];\n\n/// @returns an array of objects describing web3.eth api properties\n\n\n\nvar properties = [\n new Property({\n name: 'coinbase',\n getter: 'eth_coinbase'\n }),\n new Property({\n name: 'mining',\n getter: 'eth_mining'\n }),\n new Property({\n name: 'hashrate',\n getter: 'eth_hashrate',\n outputFormatter: utils.toDecimal\n }),\n new Property({\n name: 'gasPrice',\n getter: 'eth_gasPrice',\n outputFormatter: formatters.outputBigNumberFormatter\n }),\n new Property({\n name: 'accounts',\n getter: 'eth_accounts'\n }),\n new Property({\n name: 'blockNumber',\n getter: 'eth_blockNumber',\n outputFormatter: utils.toDecimal\n })\n];\n\nmodule.exports = {\n methods: methods,\n properties: properties\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file event.js\n * @author Marek Kotewicz \n * @date 2014\n */\n\nvar utils = require('../utils/utils');\nvar coder = require('../solidity/coder');\nvar web3 = require('../web3');\nvar formatters = require('./formatters');\n\n/**\n * This prototype should be used to create event filters\n */\nvar SolidityEvent = function (json, address) {\n this._params = json.inputs;\n this._name = utils.transformToFullName(json);\n this._address = address;\n this._anonymous = json.anonymous;\n};\n\n/**\n * Should be used to get filtered param types\n *\n * @method types\n * @param {Bool} decide if returned typed should be indexed\n * @return {Array} array of types\n */\nSolidityEvent.prototype.types = function (indexed) {\n return this._params.filter(function (i) {\n return i.indexed === indexed;\n }).map(function (i) {\n return i.type;\n });\n};\n\n/**\n * Should be used to get event display name\n *\n * @method displayName\n * @return {String} event display name\n */\nSolidityEvent.prototype.displayName = function () {\n return utils.extractDisplayName(this._name);\n};\n\n/**\n * Should be used to get event type name\n *\n * @method typeName\n * @return {String} event type name\n */\nSolidityEvent.prototype.typeName = function () {\n return utils.extractTypeName(this._name);\n};\n\n/**\n * Should be used to get event signature\n *\n * @method signature\n * @return {String} event signature\n */\nSolidityEvent.prototype.signature = function () {\n return web3.sha3(web3.fromAscii(this._name)).slice(2);\n};\n\n/**\n * Should be used to encode indexed params and options to one final object\n * \n * @method encode\n * @param {Object} indexed\n * @param {Object} options\n * @return {Object} everything combined together and encoded\n */\nSolidityEvent.prototype.encode = function (indexed, options) {\n indexed = indexed || {};\n options = options || {};\n var result = {};\n\n ['fromBlock', 'toBlock'].filter(function (f) {\n return options[f] !== undefined;\n }).forEach(function (f) {\n result[f] = formatters.inputBlockNumberFormatter(options[f]);\n });\n\n result.topics = [];\n\n if (!this._anonymous) {\n result.address = this._address;\n result.topics.push('0x' + this.signature());\n }\n\n var indexedTopics = this._params.filter(function (i) {\n return i.indexed === true;\n }).map(function (i) {\n var value = indexed[i.name];\n if (value === undefined || value === null) {\n return null;\n }\n \n if (utils.isArray(value)) {\n return value.map(function (v) {\n return '0x' + coder.encodeParam(i.type, v);\n });\n }\n return '0x' + coder.encodeParam(i.type, value);\n });\n\n result.topics = result.topics.concat(indexedTopics);\n\n return result;\n};\n\n/**\n * Should be used to decode indexed params and options\n *\n * @method decode\n * @param {Object} data\n * @return {Object} result object with decoded indexed && not indexed params\n */\nSolidityEvent.prototype.decode = function (data) {\n \n data.data = data.data || '';\n data.topics = data.topics || [];\n\n var argTopics = this._anonymous ? data.topics : data.topics.slice(1);\n var indexedData = argTopics.map(function (topics) { return topics.slice(2); }).join(\"\");\n var indexedParams = coder.decodeParams(this.types(true), indexedData); \n\n var notIndexedData = data.data.slice(2);\n var notIndexedParams = coder.decodeParams(this.types(false), notIndexedData);\n \n var result = formatters.outputLogFormatter(data);\n result.event = this.displayName();\n result.address = data.address;\n\n result.args = this._params.reduce(function (acc, current) {\n acc[current.name] = current.indexed ? indexedParams.shift() : notIndexedParams.shift();\n return acc;\n }, {});\n\n delete result.data;\n delete result.topics;\n\n return result;\n};\n\n/**\n * Should be used to create new filter object from event\n *\n * @method execute\n * @param {Object} indexed\n * @param {Object} options\n * @return {Object} filter object\n */\nSolidityEvent.prototype.execute = function (indexed, options) {\n var o = this.encode(indexed, options);\n var formatter = this.decode.bind(this);\n return web3.eth.filter(o, undefined, undefined, formatter);\n};\n\n/**\n * Should be used to attach event to contract object\n *\n * @method attachToContract\n * @param {Contract}\n */\nSolidityEvent.prototype.attachToContract = function (contract) {\n var execute = this.execute.bind(this);\n var displayName = this.displayName();\n if (!contract[displayName]) {\n contract[displayName] = execute;\n }\n contract[displayName][this.typeName()] = this.execute.bind(this, contract);\n};\n\nmodule.exports = SolidityEvent;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file filter.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Fabian Vogelsteller \n * Gav Wood \n * @date 2014\n */\n\nvar RequestManager = require('./requestmanager');\nvar formatters = require('./formatters');\nvar utils = require('../utils/utils');\n\n/**\n* Converts a given topic to a hex string, but also allows null values.\n*\n* @param {Mixed} value\n* @return {String}\n*/\nvar toTopic = function(value){\n\n if(value === null || typeof value === 'undefined')\n return null;\n\n value = String(value);\n\n if(value.indexOf('0x') === 0)\n return value;\n else\n return utils.fromAscii(value);\n};\n\n/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones\n/// @param should be string or object\n/// @returns options string or object\nvar getOptions = function (options) {\n\n if (utils.isString(options)) {\n return options;\n } \n\n options = options || {};\n\n // make sure topics, get converted to hex\n options.topics = options.topics || [];\n options.topics = options.topics.map(function(topic){\n return (utils.isArray(topic)) ? topic.map(toTopic) : toTopic(topic);\n });\n\n // lazy load\n return {\n topics: options.topics,\n to: options.to,\n address: options.address,\n fromBlock: formatters.inputBlockNumberFormatter(options.fromBlock),\n toBlock: formatters.inputBlockNumberFormatter(options.toBlock) \n }; \n};\n\nvar Filter = function (options, methods, formatter) {\n var implementation = {};\n methods.forEach(function (method) {\n method.attachToObject(implementation);\n });\n this.options = getOptions(options);\n this.implementation = implementation;\n this.callbacks = [];\n this.formatter = formatter;\n this.filterId = this.implementation.newFilter(this.options);\n};\n\nFilter.prototype.watch = function (callback) {\n this.callbacks.push(callback);\n var self = this;\n\n var onMessage = function (error, messages) {\n if (error) {\n return self.callbacks.forEach(function (callback) {\n callback(error);\n });\n }\n\n messages.forEach(function (message) {\n message = self.formatter ? self.formatter(message) : message;\n self.callbacks.forEach(function (callback) {\n callback(null, message);\n });\n });\n };\n\n // call getFilterLogs on start\n if (!utils.isString(this.options)) {\n this.get(function (err, messages) {\n // don't send all the responses to all the watches again... just to this one\n if (err) {\n callback(err);\n }\n\n messages.forEach(function (message) {\n callback(null, message);\n });\n });\n }\n\n RequestManager.getInstance().startPolling({\n method: this.implementation.poll.call,\n params: [this.filterId],\n }, this.filterId, onMessage, this.stopWatching.bind(this));\n};\n\nFilter.prototype.stopWatching = function () {\n RequestManager.getInstance().stopPolling(this.filterId);\n this.implementation.uninstallFilter(this.filterId);\n this.callbacks = [];\n};\n\nFilter.prototype.get = function (callback) {\n var self = this;\n if (utils.isFunction(callback)) {\n this.implementation.getLogs(this.filterId, function(err, res){\n if (err) {\n callback(err);\n } else {\n callback(null, res.map(function (log) {\n return self.formatter ? self.formatter(log) : log;\n }));\n }\n });\n } else {\n var logs = this.implementation.getLogs(this.filterId);\n return logs.map(function (log) {\n return self.formatter ? self.formatter(log) : log;\n });\n }\n};\n\nmodule.exports = Filter;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file formatters.js\n * @author Marek Kotewicz \n * @author Fabian Vogelsteller \n * @date 2015\n */\n\nvar utils = require('../utils/utils');\nvar config = require('../utils/config');\n\n/**\n * Should the format output to a big number\n *\n * @method outputBigNumberFormatter\n * @param {String|Number|BigNumber}\n * @returns {BigNumber} object\n */\nvar outputBigNumberFormatter = function (number) {\n return utils.toBigNumber(number);\n};\n\nvar isPredefinedBlockNumber = function (blockNumber) {\n return blockNumber === 'latest' || blockNumber === 'pending' || blockNumber === 'earliest';\n};\n\nvar inputDefaultBlockNumberFormatter = function (blockNumber) {\n if (blockNumber === undefined) {\n return config.defaultBlock;\n }\n return inputBlockNumberFormatter(blockNumber);\n};\n\nvar inputBlockNumberFormatter = function (blockNumber) {\n if (blockNumber === undefined) {\n return undefined;\n } else if (isPredefinedBlockNumber(blockNumber)) {\n return blockNumber;\n }\n return utils.toHex(blockNumber);\n};\n\n/**\n * Formats the input of a transaction and converts all values to HEX\n *\n * @method inputTransactionFormatter\n * @param {Object} transaction options\n * @returns object\n*/\nvar inputTransactionFormatter = function (options){\n\n options.from = options.from || config.defaultAccount;\n\n // make code -> data\n if (options.code) {\n options.data = options.code;\n delete options.code;\n }\n\n ['gasPrice', 'gas', 'value', 'nonce'].filter(function (key) {\n return options[key] !== undefined;\n }).forEach(function(key){\n options[key] = utils.fromDecimal(options[key]);\n });\n\n return options; \n};\n\n/**\n * Formats the output of a transaction to its proper values\n * \n * @method outputTransactionFormatter\n * @param {Object} transaction\n * @returns {Object} transaction\n*/\nvar outputTransactionFormatter = function (tx){\n tx.blockNumber = utils.toDecimal(tx.blockNumber);\n tx.transactionIndex = utils.toDecimal(tx.transactionIndex);\n tx.nonce = utils.toDecimal(tx.nonce);\n tx.gas = utils.toDecimal(tx.gas);\n tx.gasPrice = utils.toBigNumber(tx.gasPrice);\n tx.value = utils.toBigNumber(tx.value);\n return tx;\n};\n\n/**\n * Formats the output of a block to its proper values\n *\n * @method outputBlockFormatter\n * @param {Object} block object \n * @returns {Object} block object\n*/\nvar outputBlockFormatter = function(block) {\n\n // transform to number\n block.gasLimit = utils.toDecimal(block.gasLimit);\n block.gasUsed = utils.toDecimal(block.gasUsed);\n block.size = utils.toDecimal(block.size);\n block.timestamp = utils.toDecimal(block.timestamp);\n block.number = utils.toDecimal(block.number);\n\n block.difficulty = utils.toBigNumber(block.difficulty);\n block.totalDifficulty = utils.toBigNumber(block.totalDifficulty);\n\n if (utils.isArray(block.transactions)) {\n block.transactions.forEach(function(item){\n if(!utils.isString(item))\n return outputTransactionFormatter(item);\n });\n }\n\n return block;\n};\n\n/**\n * Formats the output of a log\n * \n * @method outputLogFormatter\n * @param {Object} log object\n * @returns {Object} log\n*/\nvar outputLogFormatter = function(log) {\n if (log === null) { // 'pending' && 'latest' filters are nulls\n return null;\n }\n\n log.blockNumber = utils.toDecimal(log.blockNumber);\n log.transactionIndex = utils.toDecimal(log.transactionIndex);\n log.logIndex = utils.toDecimal(log.logIndex);\n\n return log;\n};\n\n/**\n * Formats the input of a whisper post and converts all values to HEX\n *\n * @method inputPostFormatter\n * @param {Object} transaction object\n * @returns {Object}\n*/\nvar inputPostFormatter = function(post) {\n\n post.payload = utils.toHex(post.payload);\n post.ttl = utils.fromDecimal(post.ttl);\n post.workToProve = utils.fromDecimal(post.workToProve);\n post.priority = utils.fromDecimal(post.priority);\n\n // fallback\n if (!utils.isArray(post.topics)) {\n post.topics = post.topics ? [post.topics] : [];\n }\n\n // format the following options\n post.topics = post.topics.map(function(topic){\n return utils.fromAscii(topic);\n });\n\n return post; \n};\n\n/**\n * Formats the output of a received post message\n *\n * @method outputPostFormatter\n * @param {Object}\n * @returns {Object}\n */\nvar outputPostFormatter = function(post){\n\n post.expiry = utils.toDecimal(post.expiry);\n post.sent = utils.toDecimal(post.sent);\n post.ttl = utils.toDecimal(post.ttl);\n post.workProved = utils.toDecimal(post.workProved);\n post.payloadRaw = post.payload;\n post.payload = utils.toAscii(post.payload);\n\n if (utils.isJson(post.payload)) {\n post.payload = JSON.parse(post.payload);\n }\n\n // format the following options\n if (!post.topics) {\n post.topics = [];\n }\n post.topics = post.topics.map(function(topic){\n return utils.toAscii(topic);\n });\n\n return post;\n};\n\nmodule.exports = {\n inputDefaultBlockNumberFormatter: inputDefaultBlockNumberFormatter,\n inputBlockNumberFormatter: inputBlockNumberFormatter,\n inputTransactionFormatter: inputTransactionFormatter,\n inputPostFormatter: inputPostFormatter,\n outputBigNumberFormatter: outputBigNumberFormatter,\n outputTransactionFormatter: outputTransactionFormatter,\n outputBlockFormatter: outputBlockFormatter,\n outputLogFormatter: outputLogFormatter,\n outputPostFormatter: outputPostFormatter\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file function.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar web3 = require('../web3');\nvar coder = require('../solidity/coder');\nvar utils = require('../utils/utils');\n\n/**\n * This prototype should be used to call/sendTransaction to solidity functions\n */\nvar SolidityFunction = function (json, address) {\n this._inputTypes = json.inputs.map(function (i) {\n return i.type;\n });\n this._outputTypes = json.outputs.map(function (i) {\n return i.type;\n });\n this._constant = json.constant;\n this._name = utils.transformToFullName(json);\n this._address = address;\n};\n\nSolidityFunction.prototype.extractCallback = function (args) {\n if (utils.isFunction(args[args.length - 1])) {\n return args.pop(); // modify the args array!\n }\n};\n\n/**\n * Should be used to create payload from arguments\n *\n * @method toPayload\n * @param {Array} solidity function params\n * @param {Object} optional payload options\n */\nSolidityFunction.prototype.toPayload = function (args) {\n var options = {};\n if (args.length > this._inputTypes.length && utils.isObject(args[args.length -1])) {\n options = args[args.length - 1];\n }\n options.to = this._address;\n options.data = '0x' + this.signature() + coder.encodeParams(this._inputTypes, args);\n return options;\n};\n\n/**\n * Should be used to get function signature\n *\n * @method signature\n * @return {String} function signature\n */\nSolidityFunction.prototype.signature = function () {\n return web3.sha3(web3.fromAscii(this._name)).slice(2, 10);\n};\n\n\nSolidityFunction.prototype.unpackOutput = function (output) {\n if (output === null) {\n return;\n }\n\n output = output.length >= 2 ? output.slice(2) : output;\n var result = coder.decodeParams(this._outputTypes, output);\n return result.length === 1 ? result[0] : result;\n};\n\n/**\n * Calls a contract function.\n *\n * @method call\n * @param {...Object} Contract function arguments\n * @param {function} If the last argument is a function, the contract function\n * call will be asynchronous, and the callback will be passed the\n * error and result.\n * @return {String} output bytes\n */\nSolidityFunction.prototype.call = function () {\n var args = Array.prototype.slice.call(arguments);\n var callback = this.extractCallback(args);\n var payload = this.toPayload(args);\n\n if (!callback) {\n var output = web3.eth.call(payload);\n return this.unpackOutput(output);\n } \n \n var self = this;\n web3.eth.call(payload, function (error, output) {\n callback(error, self.unpackOutput(output));\n });\n};\n\n/**\n * Should be used to sendTransaction to solidity function\n *\n * @method sendTransaction\n * @param {Object} options\n */\nSolidityFunction.prototype.sendTransaction = function () {\n var args = Array.prototype.slice.call(arguments);\n var callback = this.extractCallback(args);\n var payload = this.toPayload(args);\n\n if (!callback) {\n web3.eth.sendTransaction(payload);\n return;\n }\n\n web3.eth.sendTransaction(payload, callback);\n};\n\n/**\n * Should be used to get function display name\n *\n * @method displayName\n * @return {String} display name of the function\n */\nSolidityFunction.prototype.displayName = function () {\n return utils.extractDisplayName(this._name);\n};\n\n/**\n * Should be used to get function type name\n *\n * @method typeName\n * @return {String} type name of the function\n */\nSolidityFunction.prototype.typeName = function () {\n return utils.extractTypeName(this._name);\n};\n\n/**\n * Should be called to get rpc requests from solidity function\n *\n * @method request\n * @returns {Object}\n */\nSolidityFunction.prototype.request = function () {\n var args = Array.prototype.slice.call(arguments);\n var callback = this.extractCallback(args);\n var payload = this.toPayload(args);\n var format = this.unpackOutput.bind(this);\n \n return {\n callback: callback,\n payload: payload, \n format: format\n };\n};\n\n/**\n * Should be called to execute function\n *\n * @method execute\n */\nSolidityFunction.prototype.execute = function () {\n var transaction = !this._constant;\n\n // send transaction\n if (transaction) {\n return this.sendTransaction.apply(this, Array.prototype.slice.call(arguments));\n }\n\n // call\n return this.call.apply(this, Array.prototype.slice.call(arguments));\n};\n\n/**\n * Should be called to attach function to contract\n *\n * @method attachToContract\n * @param {Contract}\n */\nSolidityFunction.prototype.attachToContract = function (contract) {\n var execute = this.execute.bind(this);\n execute.request = this.request.bind(this);\n execute.call = this.call.bind(this);\n execute.sendTransaction = this.sendTransaction.bind(this);\n var displayName = this.displayName();\n if (!contract[displayName]) {\n contract[displayName] = execute;\n }\n contract[displayName][this.typeName()] = execute; // circular!!!!\n};\n\nmodule.exports = SolidityFunction;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file httpprovider.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * Fabian Vogelsteller \n * @date 2014\n */\n\n\"use strict\";\n\nvar XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line\nvar errors = require('./errors');\n\nvar HttpProvider = function (host) {\n this.host = host || 'http://localhost:8545';\n};\n\nHttpProvider.prototype.send = function (payload) {\n var request = new XMLHttpRequest();\n\n request.open('POST', this.host, false);\n \n try {\n request.send(JSON.stringify(payload));\n } catch(error) {\n throw errors.InvalidConnection(this.host);\n }\n\n\n // check request.status\n // TODO: throw an error here! it cannot silently fail!!!\n //if (request.status !== 200) {\n //return;\n //}\n\n var result = request.responseText;\n\n try {\n result = JSON.parse(result);\n } catch(e) {\n throw errors.InvalidResponse(result); \n }\n\n return result;\n};\n\nHttpProvider.prototype.sendAsync = function (payload, callback) {\n var request = new XMLHttpRequest();\n request.onreadystatechange = function() {\n if (request.readyState === 4) {\n var result = request.responseText;\n var error = null;\n\n try {\n result = JSON.parse(result);\n } catch(e) {\n error = errors.InvalidResponse(result); \n }\n\n callback(error, result);\n }\n };\n\n request.open('POST', this.host, true);\n\n try {\n request.send(JSON.stringify(payload));\n } catch(error) {\n callback(errors.InvalidConnection(this.host));\n }\n};\n\nmodule.exports = HttpProvider;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file jsonrpc.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar Jsonrpc = function () {\n // singleton pattern\n if (arguments.callee._singletonInstance) {\n return arguments.callee._singletonInstance;\n }\n arguments.callee._singletonInstance = this;\n\n this.messageId = 1;\n};\n\n/**\n * @return {Jsonrpc} singleton\n */\nJsonrpc.getInstance = function () {\n var instance = new Jsonrpc();\n return instance;\n};\n\n/**\n * Should be called to valid json create payload object\n *\n * @method toPayload\n * @param {Function} method of jsonrpc call, required\n * @param {Array} params, an array of method params, optional\n * @returns {Object} valid jsonrpc payload object\n */\nJsonrpc.prototype.toPayload = function (method, params) {\n if (!method)\n console.error('jsonrpc method should be specified!');\n\n return {\n jsonrpc: '2.0',\n method: method,\n params: params || [],\n id: this.messageId++\n };\n};\n\n/**\n * Should be called to check if jsonrpc response is valid\n *\n * @method isValidResponse\n * @param {Object}\n * @returns {Boolean} true if response is valid, otherwise false\n */\nJsonrpc.prototype.isValidResponse = function (response) {\n return !!response &&\n !response.error &&\n response.jsonrpc === '2.0' &&\n typeof response.id === 'number' &&\n response.result !== undefined; // only undefined is not valid json object\n};\n\n/**\n * Should be called to create batch payload object\n *\n * @method toBatchPayload\n * @param {Array} messages, an array of objects with method (required) and params (optional) fields\n * @returns {Array} batch payload\n */\nJsonrpc.prototype.toBatchPayload = function (messages) {\n var self = this;\n return messages.map(function (message) {\n return self.toPayload(message.method, message.params);\n });\n};\n\nmodule.exports = Jsonrpc;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file method.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar RequestManager = require('./requestmanager');\nvar utils = require('../utils/utils');\nvar errors = require('./errors');\n\nvar Method = function (options) {\n this.name = options.name;\n this.call = options.call;\n this.params = options.params || 0;\n this.inputFormatter = options.inputFormatter;\n this.outputFormatter = options.outputFormatter;\n};\n\n/**\n * Should be used to determine name of the jsonrpc method based on arguments\n *\n * @method getCall\n * @param {Array} arguments\n * @return {String} name of jsonrpc method\n */\nMethod.prototype.getCall = function (args) {\n return utils.isFunction(this.call) ? this.call(args) : this.call;\n};\n\n/**\n * Should be used to extract callback from array of arguments. Modifies input param\n *\n * @method extractCallback\n * @param {Array} arguments\n * @return {Function|Null} callback, if exists\n */\nMethod.prototype.extractCallback = function (args) {\n if (utils.isFunction(args[args.length - 1])) {\n return args.pop(); // modify the args array!\n }\n};\n\n/**\n * Should be called to check if the number of arguments is correct\n * \n * @method validateArgs\n * @param {Array} arguments\n * @throws {Error} if it is not\n */\nMethod.prototype.validateArgs = function (args) {\n if (args.length !== this.params) {\n throw errors.InvalidNumberOfParams();\n }\n};\n\n/**\n * Should be called to format input args of method\n * \n * @method formatInput\n * @param {Array}\n * @return {Array}\n */\nMethod.prototype.formatInput = function (args) {\n if (!this.inputFormatter) {\n return args;\n }\n\n return this.inputFormatter.map(function (formatter, index) {\n return formatter ? formatter(args[index]) : args[index];\n });\n};\n\n/**\n * Should be called to format output(result) of method\n *\n * @method formatOutput\n * @param {Object}\n * @return {Object}\n */\nMethod.prototype.formatOutput = function (result) {\n return this.outputFormatter && result !== null ? this.outputFormatter(result) : result;\n};\n\n/**\n * Should attach function to method\n * \n * @method attachToObject\n * @param {Object}\n * @param {Function}\n */\nMethod.prototype.attachToObject = function (obj) {\n var func = this.send.bind(this);\n func.request = this.request.bind(this);\n func.call = this.call; // that's ugly. filter.js uses it\n var name = this.name.split('.');\n if (name.length > 1) {\n obj[name[0]] = obj[name[0]] || {};\n obj[name[0]][name[1]] = func;\n } else {\n obj[name[0]] = func; \n }\n};\n\n/**\n * Should create payload from given input args\n *\n * @method toPayload\n * @param {Array} args\n * @return {Object}\n */\nMethod.prototype.toPayload = function (args) {\n var call = this.getCall(args);\n var callback = this.extractCallback(args);\n var params = this.formatInput(args);\n this.validateArgs(params);\n\n return {\n method: call,\n params: params,\n callback: callback\n };\n};\n\n/**\n * Should be called to create pure JSONRPC request which can be used in batch request\n *\n * @method request\n * @param {...} params\n * @return {Object} jsonrpc request\n */\nMethod.prototype.request = function () {\n var payload = this.toPayload(Array.prototype.slice.call(arguments));\n payload.format = this.formatOutput.bind(this);\n return payload;\n};\n\n/**\n * Should send request to the API\n *\n * @method send\n * @param list of params\n * @return result\n */\nMethod.prototype.send = function () {\n var payload = this.toPayload(Array.prototype.slice.call(arguments));\n if (payload.callback) {\n var self = this;\n return RequestManager.getInstance().sendAsync(payload, function (err, result) {\n payload.callback(err, self.formatOutput(result));\n });\n }\n return this.formatOutput(RequestManager.getInstance().send(payload));\n};\n\nmodule.exports = Method;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file eth.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar utils = require('../utils/utils');\nvar Property = require('./property');\n\n/// @returns an array of objects describing web3.eth api methods\nvar methods = [\n];\n\n/// @returns an array of objects describing web3.eth api properties\nvar properties = [\n new Property({\n name: 'listening',\n getter: 'net_listening'\n }),\n new Property({\n name: 'peerCount',\n getter: 'net_peerCount',\n outputFormatter: utils.toDecimal\n })\n];\n\n\nmodule.exports = {\n methods: methods,\n properties: properties\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file property.js\n * @author Fabian Vogelsteller \n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar RequestManager = require('./requestmanager');\n\nvar Property = function (options) {\n this.name = options.name;\n this.getter = options.getter;\n this.setter = options.setter;\n this.outputFormatter = options.outputFormatter;\n this.inputFormatter = options.inputFormatter;\n};\n\n/**\n * Should be called to format input args of method\n * \n * @method formatInput\n * @param {Array}\n * @return {Array}\n */\nProperty.prototype.formatInput = function (arg) {\n return this.inputFormatter ? this.inputFormatter(arg) : arg;\n};\n\n/**\n * Should be called to format output(result) of method\n *\n * @method formatOutput\n * @param {Object}\n * @return {Object}\n */\nProperty.prototype.formatOutput = function (result) {\n return this.outputFormatter && result !== null ? this.outputFormatter(result) : result;\n};\n\n/**\n * Should attach function to method\n * \n * @method attachToObject\n * @param {Object}\n * @param {Function}\n */\nProperty.prototype.attachToObject = function (obj) {\n var proto = {\n get: this.get.bind(this),\n };\n\n var names = this.name.split('.');\n var name = names[0];\n if (names.length > 1) {\n obj[names[0]] = obj[names[0]] || {};\n obj = obj[names[0]];\n name = names[1];\n }\n \n Object.defineProperty(obj, name, proto);\n\n var toAsyncName = function (prefix, name) {\n return prefix + name.charAt(0).toUpperCase() + name.slice(1);\n };\n\n obj[toAsyncName('get', name)] = this.getAsync.bind(this);\n};\n\n/**\n * Should be used to get value of the property\n *\n * @method get\n * @return {Object} value of the property\n */\nProperty.prototype.get = function () {\n return this.formatOutput(RequestManager.getInstance().send({\n method: this.getter\n }));\n};\n\n/**\n * Should be used to asynchrounously get value of property\n *\n * @method getAsync\n * @param {Function}\n */\nProperty.prototype.getAsync = function (callback) {\n var self = this;\n RequestManager.getInstance().sendAsync({\n method: this.getter\n }, function (err, result) {\n if (err) {\n return callback(err);\n }\n callback(err, self.formatOutput(result));\n });\n};\n\nmodule.exports = Property;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file qtsync.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\nvar QtSyncProvider = function () {\n};\n\nQtSyncProvider.prototype.send = function (payload) {\n var result = navigator.qt.callMethod(JSON.stringify(payload));\n return JSON.parse(result);\n};\n\nmodule.exports = QtSyncProvider;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file requestmanager.js\n * @author Jeffrey Wilcke \n * @author Marek Kotewicz \n * @author Marian Oancea \n * @author Fabian Vogelsteller \n * @author Gav Wood \n * @date 2014\n */\n\nvar Jsonrpc = require('./jsonrpc');\nvar utils = require('../utils/utils');\nvar c = require('../utils/config');\nvar errors = require('./errors');\n\n/**\n * It's responsible for passing messages to providers\n * It's also responsible for polling the ethereum node for incoming messages\n * Default poll timeout is 1 second\n * Singleton\n */\nvar RequestManager = function (provider) {\n // singleton pattern\n if (arguments.callee._singletonInstance) {\n return arguments.callee._singletonInstance;\n }\n arguments.callee._singletonInstance = this;\n\n this.provider = provider;\n this.polls = [];\n this.timeout = null;\n this.poll();\n};\n\n/**\n * @return {RequestManager} singleton\n */\nRequestManager.getInstance = function () {\n var instance = new RequestManager();\n return instance;\n};\n\n/**\n * Should be used to synchronously send request\n *\n * @method send\n * @param {Object} data\n * @return {Object}\n */\nRequestManager.prototype.send = function (data) {\n if (!this.provider) {\n console.error(errors.InvalidProvider());\n return null;\n }\n\n var payload = Jsonrpc.getInstance().toPayload(data.method, data.params);\n var result = this.provider.send(payload);\n\n if (!Jsonrpc.getInstance().isValidResponse(result)) {\n throw errors.InvalidResponse(result);\n }\n\n return result.result;\n};\n\n/**\n * Should be used to asynchronously send request\n *\n * @method sendAsync\n * @param {Object} data\n * @param {Function} callback\n */\nRequestManager.prototype.sendAsync = function (data, callback) {\n if (!this.provider) {\n return callback(errors.InvalidProvider());\n }\n\n var payload = Jsonrpc.getInstance().toPayload(data.method, data.params);\n this.provider.sendAsync(payload, function (err, result) {\n if (err) {\n return callback(err);\n }\n \n if (!Jsonrpc.getInstance().isValidResponse(result)) {\n return callback(errors.InvalidResponse(result));\n }\n\n callback(null, result.result);\n });\n};\n\n/**\n * Should be called to asynchronously send batch request\n *\n * @method sendBatch\n * @param {Array} batch data\n * @param {Function} callback\n */\nRequestManager.prototype.sendBatch = function (data, callback) {\n if (!this.provider) {\n return callback(errors.InvalidProvider());\n }\n\n var payload = Jsonrpc.getInstance().toBatchPayload(data);\n\n this.provider.sendAsync(payload, function (err, results) {\n if (err) {\n return callback(err);\n }\n\n if (!utils.isArray(results)) {\n return callback(errors.InvalidResponse(results));\n }\n\n callback(err, results);\n }); \n};\n\n/**\n * Should be used to set provider of request manager\n *\n * @method setProvider\n * @param {Object}\n */\nRequestManager.prototype.setProvider = function (p) {\n this.provider = p;\n};\n\n/*jshint maxparams:4 */\n\n/**\n * Should be used to start polling\n *\n * @method startPolling\n * @param {Object} data\n * @param {Number} pollId\n * @param {Function} callback\n * @param {Function} uninstall\n *\n * @todo cleanup number of params\n */\nRequestManager.prototype.startPolling = function (data, pollId, callback, uninstall) {\n this.polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall});\n};\n/*jshint maxparams:3 */\n\n/**\n * Should be used to stop polling for filter with given id\n *\n * @method stopPolling\n * @param {Number} pollId\n */\nRequestManager.prototype.stopPolling = function (pollId) {\n for (var i = this.polls.length; i--;) {\n var poll = this.polls[i];\n if (poll.id === pollId) {\n this.polls.splice(i, 1);\n }\n }\n};\n\n/**\n * Should be called to reset polling mechanism of request manager\n *\n * @method reset\n */\nRequestManager.prototype.reset = function () {\n this.polls.forEach(function (poll) {\n poll.uninstall(poll.id); \n });\n this.polls = [];\n\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = null;\n }\n this.poll();\n};\n\n/**\n * Should be called to poll for changes on filter with given id\n *\n * @method poll\n */\nRequestManager.prototype.poll = function () {\n this.timeout = setTimeout(this.poll.bind(this), c.ETH_POLLING_TIMEOUT);\n\n if (!this.polls.length) {\n return;\n }\n\n if (!this.provider) {\n console.error(errors.InvalidProvider());\n return;\n }\n\n var payload = Jsonrpc.getInstance().toBatchPayload(this.polls.map(function (data) {\n return data.data;\n }));\n\n var self = this;\n this.provider.sendAsync(payload, function (error, results) {\n // TODO: console log?\n if (error) {\n return;\n }\n \n if (!utils.isArray(results)) {\n throw errors.InvalidResponse(results);\n }\n\n results.map(function (result, index) {\n result.callback = self.polls[index].callback;\n return result;\n }).filter(function (result) {\n var valid = Jsonrpc.getInstance().isValidResponse(result);\n if (!valid) {\n result.callback(errors.InvalidResponse(result));\n }\n return valid;\n }).filter(function (result) {\n return utils.isArray(result.result) && result.result.length > 0;\n }).forEach(function (result) {\n result.callback(null, result.result);\n });\n });\n};\n\nmodule.exports = RequestManager;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file shh.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar Method = require('./method');\nvar formatters = require('./formatters');\n\nvar post = new Method({\n name: 'post', \n call: 'shh_post', \n params: 1,\n inputFormatter: [formatters.inputPostFormatter]\n});\n\nvar newIdentity = new Method({\n name: 'newIdentity',\n call: 'shh_newIdentity',\n params: 0\n});\n\nvar hasIdentity = new Method({\n name: 'hasIdentity',\n call: 'shh_hasIdentity',\n params: 1\n});\n\nvar newGroup = new Method({\n name: 'newGroup',\n call: 'shh_newGroup',\n params: 0\n});\n\nvar addToGroup = new Method({\n name: 'addToGroup',\n call: 'shh_addToGroup',\n params: 0\n});\n\nvar methods = [\n post,\n newIdentity,\n hasIdentity,\n newGroup,\n addToGroup\n];\n\nmodule.exports = {\n methods: methods\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file watches.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar Method = require('./method');\n\n/// @returns an array of objects describing web3.eth.filter api methods\nvar eth = function () {\n var newFilterCall = function (args) {\n var type = args[0];\n\n switch(type) {\n case 'latest':\n args.pop();\n this.params = 0;\n return 'eth_newBlockFilter';\n case 'pending':\n args.pop();\n this.params = 0;\n return 'eth_newPendingTransactionFilter';\n default:\n return 'eth_newFilter';\n }\n };\n\n var newFilter = new Method({\n name: 'newFilter',\n call: newFilterCall,\n params: 1\n });\n\n var uninstallFilter = new Method({\n name: 'uninstallFilter',\n call: 'eth_uninstallFilter',\n params: 1\n });\n\n var getLogs = new Method({\n name: 'getLogs',\n call: 'eth_getFilterLogs',\n params: 1\n });\n\n var poll = new Method({\n name: 'poll',\n call: 'eth_getFilterChanges',\n params: 1\n });\n\n return [\n newFilter,\n uninstallFilter,\n getLogs,\n poll\n ];\n};\n\n/// @returns an array of objects describing web3.shh.watch api methods\nvar shh = function () {\n var newFilter = new Method({\n name: 'newFilter',\n call: 'shh_newFilter',\n params: 1\n });\n\n var uninstallFilter = new Method({\n name: 'uninstallFilter',\n call: 'shh_uninstallFilter',\n params: 1\n });\n\n var getLogs = new Method({\n name: 'getLogs',\n call: 'shh_getMessages',\n params: 1\n });\n\n var poll = new Method({\n name: 'poll',\n call: 'shh_getFilterChanges',\n params: 1\n });\n\n return [\n newFilter,\n uninstallFilter,\n getLogs,\n poll\n ];\n};\n\nmodule.exports = {\n eth: eth,\n shh: shh\n};\n\n", - null, - "'use strict';\n\nmodule.exports = BigNumber; // jshint ignore:line\n\n", - "var web3 = require('./lib/web3');\nweb3.providers.HttpProvider = require('./lib/web3/httpprovider');\nweb3.providers.QtSyncProvider = require('./lib/web3/qtsync');\nweb3.eth.contract = require('./lib/web3/contract');\n\n// dont override global variable\nif (typeof window !== 'undefined' && typeof window.web3 === 'undefined') {\n window.web3 = web3;\n}\n\nmodule.exports = web3;\n\n" - ] -} \ No newline at end of file diff --git a/libjsqrc/ethereumjs/dist/web3-light.min.js b/libjsqrc/ethereumjs/dist/web3-light.min.js deleted file mode 100644 index 22527f18e..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 l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n?n:t)},l,l.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 l=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=l},{"../utils/utils":6,"./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)},l=function(t){var e="000000000000000000000000000000000000000000000000000000000000000"+(t?"1":"0");return new a(e)},p=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:l,formatInputReal:p,formatOutputInt:m,formatOutputUInt:h,formatOutputReal:d,formatOutputUReal:y,formatOutputBool:g,formatOutputBytes:v,formatOutputDynamicBytes:b,formatOutputAddress:w}},{"../utils/config":5,"../utils/utils":6,"./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},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))},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)))},e.exports=o},{"../utils/utils":6}],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","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("bignumber.js"),o={wei:"1",kwei:"1000",ada:"1000",mwei:"1000000",babbage:"1000000",gwei:"1000000000",shannon:"1000000000",szabo:"1000000000000",finney:"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},a.prototype.signature=function(){return r.sha3(r.fromAscii(this._name)).slice(2,10)},a.prototype.unpackOutput=function(t){if(null!==t){t=t.length>=2?t.slice(2):t;var e=o.decodeParams(this._outputTypes,t);return 1===e.length?e[0]:e}},a.prototype.call=function(){var t=Array.prototype.slice.call(arguments),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))})},a.prototype.sendTransaction=function(){var t=Array.prototype.slice.call(arguments),e=this.extractCallback(t),n=this.toPayload(t);return e?void r.eth.sendTransaction(n,e):void r.eth.sendTransaction(n)},a.prototype.displayName=function(){return i.extractDisplayName(this._name)},a.prototype.typeName=function(){return i.extractTypeName(this._name)},a.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}},a.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))},a.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);var n=this.displayName();t[n]||(t[n]=e),t[n][this.typeName()]=e},e.exports=a},{"../solidity/coder":1,"../utils/utils":6,"../web3":8}],18:[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":12,xmlhttprequest:4}],19:[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},{}],20:[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":6,"./errors":12,"./requestmanager":24}],21:[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":6,"./property":22}],22:[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":24}],23:[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},{}],24:[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":6,"./errors":12,"./jsonrpc":19}],25:[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}),l=[i,a,s,u,c];e.exports={methods:l}},{"./formatters":16,"./method":20}],26:[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":20}],27:[function(t,e,n){},{}],"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"),"undefined"!=typeof window&&"undefined"==typeof window.web3&&(window.web3=r),e.exports=r},{"./lib/web3":8,"./lib/web3/contract":10,"./lib/web3/httpprovider":18,"./lib/web3/qtsync":23}]},{},["web3"]); \ No newline at end of file diff --git a/libjsqrc/ethereumjs/dist/web3.js b/libjsqrc/ethereumjs/dist/web3.js index 2745ab36f..ec5cdfe83 100644 --- a/libjsqrc/ethereumjs/dist/web3.js +++ b/libjsqrc/ethereumjs/dist/web3.js @@ -282,7 +282,7 @@ var coder = new SolidityCoder([ module.exports = coder; -},{"../utils/utils":6,"./formatters":2,"./param":3,"bignumber.js":"bignumber.js"}],2:[function(require,module,exports){ +},{"../utils/utils":7,"./formatters":2,"./param":3,"bignumber.js":"bignumber.js"}],2:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -502,7 +502,7 @@ module.exports = { }; -},{"../utils/config":5,"../utils/utils":6,"./param":3,"bignumber.js":"bignumber.js"}],3:[function(require,module,exports){ +},{"../utils/config":5,"../utils/utils":7,"./param":3,"bignumber.js":"bignumber.js"}],3:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -577,7 +577,7 @@ SolidityParam.prototype.combine = function (param) { * @returns {Boolean} */ SolidityParam.prototype.isDynamic = function () { - return this.value.length > 64; + return this.value.length > 64 || this.offset !== undefined; }; /** @@ -693,7 +693,7 @@ SolidityParam.decodeBytes = function (bytes, index) { var offset = getOffset(bytes, index); // 2 * , cause we also parse length - return new SolidityParam(bytes.substr(offset * 2, 2 * 64)); + return new SolidityParam(bytes.substr(offset * 2, 2 * 64), 0); }; /** @@ -708,13 +708,13 @@ 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)); + return new SolidityParam(bytes.substr(offset * 2, (length + 1) * 64), 0); }; module.exports = SolidityParam; -},{"../utils/utils":6}],4:[function(require,module,exports){ +},{"../utils/utils":7}],4:[function(require,module,exports){ 'use strict'; // go env doesn't have and need XMLHttpRequest @@ -764,26 +764,34 @@ if (typeof XMLHttpRequest === 'undefined') { /// required to define ETH_BIGNUMBER_ROUNDING_MODE var BigNumber = require('bignumber.js'); -var ETH_UNITS = [ - 'wei', - 'Kwei', - 'Mwei', - 'Gwei', - 'szabo', - 'finney', - 'ether', - 'grand', - 'Mether', - 'Gether', - 'Tether', - 'Pether', - 'Eether', - 'Zether', - 'Yether', - 'Nether', - 'Dether', - 'Vether', - 'Uether' +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 = { @@ -814,6 +822,47 @@ module.exports = { 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 @@ -836,22 +885,30 @@ module.exports = { var BigNumber = require('bignumber.js'); var unitMap = { - 'wei': '1', - 'kwei': '1000', - 'ada': '1000', - 'mwei': '1000000', - 'babbage': '1000000', - 'gwei': '1000000000', - 'shannon': '1000000000', - 'szabo': '1000000000000', - 'finney': '1000000000000000', - 'ether': '1000000000000000000', - 'kether': '1000000000000000000000', - 'grand': '1000000000000000000000', - 'einstein': '1000000000000000000000', - 'mether': '1000000000000000000000000', - 'gether': '1000000000000000000000000000', - 'tether': '1000000000000000000000000000000' + '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' }; /** @@ -1039,13 +1096,14 @@ var getValueOfUnit = function (unit) { * Takes a number of wei and converts it to any other ether unit. * * Possible units are: - * - kwei/ada - * - mwei/babbage - * - gwei/shannon - * - szabo - * - finney - * - ether - * - kether/grand/einstein + * 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 @@ -1065,13 +1123,14 @@ var fromWei = function(number, unit) { * Takes a number of a unit and converts it to wei. * * Possible units are: - * - kwei/ada - * - mwei/babbage - * - gwei/shannon - * - szabo - * - finney - * - ether - * - kether/grand/einstein + * 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 @@ -1247,6 +1306,18 @@ var isJson = function (str) { } }; +/** + * 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, @@ -1270,16 +1341,17 @@ module.exports = { isObject: isObject, isBoolean: isBoolean, isArray: isArray, - isJson: isJson + isJson: isJson, + isIBAN: isIBAN }; -},{"bignumber.js":"bignumber.js"}],7:[function(require,module,exports){ +},{"bignumber.js":"bignumber.js"}],8:[function(require,module,exports){ module.exports={ - "version": "0.4.2" + "version": "0.5.0" } -},{}],8:[function(require,module,exports){ +},{}],9:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1316,18 +1388,11 @@ 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 Method = require('./web3/method'); +var c = require('./utils/config'); var Property = require('./web3/property'); var Batch = require('./web3/batch'); - -var web3Methods = [ - new Method({ - name: 'sha3', - call: 'web3_sha3', - params: 1 - }) -]; +var sha3 = require('./utils/sha3'); var web3Properties = [ new Property({ @@ -1412,6 +1477,8 @@ 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(); }; @@ -1438,7 +1505,6 @@ Object.defineProperty(web3.eth, 'defaultAccount', { }); /// setups all api methods -setupMethods(web3, web3Methods); setupProperties(web3, web3Properties); setupMethods(web3.net, net.methods); setupProperties(web3.net, net.properties); @@ -1447,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/utils":6,"./version.json":7,"./web3/batch":9,"./web3/db":11,"./web3/eth":13,"./web3/filter":15,"./web3/formatters":16,"./web3/method":20,"./web3/net":21,"./web3/property":22,"./web3/requestmanager":24,"./web3/shh":25,"./web3/watches":26}],9:[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. @@ -1513,7 +1591,7 @@ Batch.prototype.execute = function () { module.exports = Batch; -},{"./requestmanager":24}],10:[function(require,module,exports){ +},{"./requestmanager":27}],11:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1695,7 +1773,7 @@ var Contract = function (abi, address) { module.exports = contract; -},{"../solidity/coder":1,"../utils/utils":6,"../web3":8,"./event":14,"./function":17}],11:[function(require,module,exports){ +},{"../solidity/coder":1,"../utils/utils":7,"../web3":9,"./event":15,"./function":18}],12:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1753,7 +1831,7 @@ module.exports = { methods: methods }; -},{"./method":20}],12:[function(require,module,exports){ +},{"./method":22}],13:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1793,7 +1871,7 @@ module.exports = { }; -},{}],13:[function(require,module,exports){ +},{}],14:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -1873,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({ @@ -2070,7 +2148,7 @@ module.exports = { }; -},{"../utils/utils":6,"./formatters":16,"./method":20,"./property":22}],14:[function(require,module,exports){ +},{"../utils/utils":7,"./formatters":17,"./method":22,"./property":25}],15:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2097,6 +2175,7 @@ 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 @@ -2150,7 +2229,7 @@ SolidityEvent.prototype.typeName = function () { * @return {String} event signature */ SolidityEvent.prototype.signature = function () { - return web3.sha3(web3.fromAscii(this._name)).slice(2); + return sha3(this._name); }; /** @@ -2266,7 +2345,7 @@ SolidityEvent.prototype.attachToContract = function (contract) { module.exports = SolidityEvent; -},{"../solidity/coder":1,"../utils/utils":6,"../web3":8,"./formatters":16}],15:[function(require,module,exports){ +},{"../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. @@ -2423,7 +2502,7 @@ Filter.prototype.get = function (callback) { module.exports = Filter; -},{"../utils/utils":6,"./formatters":16,"./requestmanager":24}],16:[function(require,module,exports){ +},{"../utils/utils":7,"./formatters":17,"./requestmanager":27}],17:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2643,7 +2722,7 @@ module.exports = { }; -},{"../utils/config":5,"../utils/utils":6}],17:[function(require,module,exports){ +},{"../utils/config":5,"../utils/utils":7}],18:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2669,6 +2748,7 @@ module.exports = { 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 @@ -2715,12 +2795,12 @@ SolidityFunction.prototype.toPayload = function (args) { * @return {String} function signature */ SolidityFunction.prototype.signature = function () { - return web3.sha3(web3.fromAscii(this._name)).slice(2, 10); + return sha3(this._name).slice(0, 8); }; SolidityFunction.prototype.unpackOutput = function (output) { - if (output === null) { + if (!output) { return; } @@ -2740,7 +2820,7 @@ SolidityFunction.prototype.unpackOutput = function (output) { * @return {String} output bytes */ SolidityFunction.prototype.call = function () { - var args = Array.prototype.slice.call(arguments); + var args = Array.prototype.slice.call(arguments).filter(function (a) {return a !== undefined; }); var callback = this.extractCallback(args); var payload = this.toPayload(args); @@ -2762,18 +2842,35 @@ SolidityFunction.prototype.call = function () { * @param {Object} options */ SolidityFunction.prototype.sendTransaction = function () { - var args = Array.prototype.slice.call(arguments); + 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) { - web3.eth.sendTransaction(payload); - return; + 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 * @@ -2841,6 +2938,7 @@ SolidityFunction.prototype.attachToContract = function (contract) { 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; @@ -2851,7 +2949,7 @@ SolidityFunction.prototype.attachToContract = function (contract) { module.exports = SolidityFunction; -},{"../solidity/coder":1,"../utils/utils":6,"../web3":8}],18:[function(require,module,exports){ +},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9}],19:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2943,7 +3041,117 @@ HttpProvider.prototype.sendAsync = function (payload, callback) { module.exports = HttpProvider; -},{"./errors":12,"xmlhttprequest":4}],19:[function(require,module,exports){ +},{"./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. @@ -3036,7 +3244,7 @@ Jsonrpc.prototype.toBatchPayload = function (messages) { module.exports = Jsonrpc; -},{}],20:[function(require,module,exports){ +},{}],22:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3210,7 +3418,55 @@ Method.prototype.send = function () { module.exports = Method; -},{"../utils/utils":6,"./errors":12,"./requestmanager":24}],21:[function(require,module,exports){ +},{"../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. @@ -3260,7 +3516,7 @@ module.exports = { }; -},{"../utils/utils":6,"./property":22}],22:[function(require,module,exports){ +},{"../utils/utils":7,"./property":25}],25:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3378,7 +3634,7 @@ Property.prototype.getAsync = function (callback) { module.exports = Property; -},{"./requestmanager":24}],23:[function(require,module,exports){ +},{"./requestmanager":27}],26:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3413,7 +3669,7 @@ QtSyncProvider.prototype.send = function (payload) { module.exports = QtSyncProvider; -},{}],24:[function(require,module,exports){ +},{}],27:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3661,7 +3917,7 @@ RequestManager.prototype.poll = function () { module.exports = RequestManager; -},{"../utils/config":5,"../utils/utils":6,"./errors":12,"./jsonrpc":19}],25:[function(require,module,exports){ +},{"../utils/config":5,"../utils/utils":7,"./errors":13,"./jsonrpc":21}],28:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -3731,7 +3987,103 @@ module.exports = { }; -},{"./formatters":16,"./method":20}],26:[function(require,module,exports){ +},{"./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. @@ -3847,9 +4199,1381 @@ module.exports = { }; -},{"./method":20}],27:[function(require,module,exports){ - -},{}],"bignumber.js":[function(require,module,exports){ +},{"./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){ /*! bignumber.js v2.0.7 https://github.com/MikeMcl/bignumber.js/LICENCE */ ;(function (global) { @@ -6534,11 +8258,13 @@ module.exports = { } })(this); -},{"crypto":27}],"web3":[function(require,module,exports){ +},{"crypto":31}],"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') { @@ -6548,7 +8274,5 @@ if (typeof window !== 'undefined' && typeof window.web3 === 'undefined') { module.exports = web3; -},{"./lib/web3":8,"./lib/web3/contract":10,"./lib/web3/httpprovider":18,"./lib/web3/qtsync":23}]},{},["web3"]) - - -//# sourceMappingURL=web3.js.map \ No newline at end of file +},{"./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,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.js.map b/libjsqrc/ethereumjs/dist/web3.js.map deleted file mode 100644 index e25fa3aed..000000000 --- a/libjsqrc/ethereumjs/dist/web3.js.map +++ /dev/null @@ -1,71 +0,0 @@ -{ - "version": 3, - "sources": [ - "node_modules/browserify/node_modules/browser-pack/_prelude.js", - "lib/solidity/coder.js", - "lib/solidity/formatters.js", - "lib/solidity/param.js", - "lib/utils/browser-xhr.js", - "lib/utils/config.js", - "lib/utils/utils.js", - "lib/version.json", - "lib/web3.js", - "lib/web3/batch.js", - "lib/web3/contract.js", - "lib/web3/db.js", - "lib/web3/errors.js", - "lib/web3/eth.js", - "lib/web3/event.js", - "lib/web3/filter.js", - "lib/web3/formatters.js", - "lib/web3/function.js", - "lib/web3/httpprovider.js", - "lib/web3/jsonrpc.js", - "lib/web3/method.js", - "lib/web3/net.js", - "lib/web3/property.js", - "lib/web3/qtsync.js", - "lib/web3/requestmanager.js", - "lib/web3/shh.js", - "lib/web3/watches.js", - "node_modules/browserify/lib/_empty.js", - "bignumber.js", - "index.js" - ], - "names": [], - "mappings": "AAAA;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1RA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClNA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACTA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3dA;AACA;AACA;AACA;;ACHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACzKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC7DA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACxDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9MA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5KA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AChDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpHA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACjCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACpEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClHA;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3nFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", - "file": "generated.js", - "sourceRoot": "", - "sourcesContent": [ - "(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.\n*/\n/** \n * @file coder.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar BigNumber = require('bignumber.js');\nvar utils = require('../utils/utils');\nvar f = require('./formatters');\nvar SolidityParam = require('./param');\n\n/**\n * Should be used to check if a type is an array type\n *\n * @method isArrayType\n * @param {String} type\n * @return {Bool} true is the type is an array, otherwise false\n */\nvar isArrayType = function (type) {\n return type.slice(-2) === '[]';\n};\n\n/**\n * SolidityType prototype is used to encode/decode solidity params of certain type\n */\nvar SolidityType = function (config) {\n this._name = config.name;\n this._match = config.match;\n this._mode = config.mode;\n this._inputFormatter = config.inputFormatter;\n this._outputFormatter = config.outputFormatter;\n};\n\n/**\n * Should be used to determine if this SolidityType do match given type\n *\n * @method isType\n * @param {String} name\n * @return {Bool} true if type match this SolidityType, otherwise false\n */\nSolidityType.prototype.isType = function (name) {\n if (this._match === 'strict') {\n return this._name === name || (name.indexOf(this._name) === 0 && name.slice(this._name.length) === '[]');\n } else if (this._match === 'prefix') {\n // TODO better type detection!\n return name.indexOf(this._name) === 0;\n }\n};\n\n/**\n * Should be used to transform plain param to SolidityParam object\n *\n * @method formatInput\n * @param {Object} param - plain object, or an array of objects\n * @param {Bool} arrayType - true if a param should be encoded as an array\n * @return {SolidityParam} encoded param wrapped in SolidityParam object \n */\nSolidityType.prototype.formatInput = function (param, arrayType) {\n if (utils.isArray(param) && arrayType) { // TODO: should fail if this two are not the same\n var self = this;\n return param.map(function (p) {\n return self._inputFormatter(p);\n }).reduce(function (acc, current) {\n return acc.combine(current);\n }, f.formatInputInt(param.length)).withOffset(32);\n } \n return this._inputFormatter(param);\n};\n\n/**\n * Should be used to transoform SolidityParam to plain param\n *\n * @method formatOutput\n * @param {SolidityParam} byteArray\n * @param {Bool} arrayType - true if a param should be decoded as an array\n * @return {Object} plain decoded param\n */\nSolidityType.prototype.formatOutput = function (param, arrayType) {\n if (arrayType) {\n // let's assume, that we solidity will never return long arrays :P \n var result = [];\n var length = new BigNumber(param.dynamicPart().slice(0, 64), 16);\n for (var i = 0; i < length * 64; i += 64) {\n result.push(this._outputFormatter(new SolidityParam(param.dynamicPart().substr(i + 64, 64))));\n }\n return result;\n }\n return this._outputFormatter(param);\n};\n\n/**\n * Should be used to slice single param from bytes\n *\n * @method sliceParam\n * @param {String} bytes\n * @param {Number} index of param to slice\n * @param {String} type\n * @returns {SolidityParam} param\n */\nSolidityType.prototype.sliceParam = function (bytes, index, type) {\n if (this._mode === 'bytes') {\n return SolidityParam.decodeBytes(bytes, index);\n } else if (isArrayType(type)) {\n return SolidityParam.decodeArray(bytes, index);\n }\n return SolidityParam.decodeParam(bytes, index);\n};\n\n/**\n * SolidityCoder prototype should be used to encode/decode solidity params of any type\n */\nvar SolidityCoder = function (types) {\n this._types = types;\n};\n\n/**\n * This method should be used to transform type to SolidityType\n *\n * @method _requireType\n * @param {String} type\n * @returns {SolidityType} \n * @throws {Error} throws if no matching type is found\n */\nSolidityCoder.prototype._requireType = function (type) {\n var solidityType = this._types.filter(function (t) {\n return t.isType(type);\n })[0];\n\n if (!solidityType) {\n throw Error('invalid solidity type!: ' + type);\n }\n\n return solidityType;\n};\n\n/**\n * Should be used to transform plain param of given type to SolidityParam\n *\n * @method _formatInput\n * @param {String} type of param\n * @param {Object} plain param\n * @return {SolidityParam}\n */\nSolidityCoder.prototype._formatInput = function (type, param) {\n return this._requireType(type).formatInput(param, isArrayType(type));\n};\n\n/**\n * Should be used to encode plain param\n *\n * @method encodeParam\n * @param {String} type\n * @param {Object} plain param\n * @return {String} encoded plain param\n */\nSolidityCoder.prototype.encodeParam = function (type, param) {\n return this._formatInput(type, param).encode();\n};\n\n/**\n * Should be used to encode list of params\n *\n * @method encodeParams\n * @param {Array} types\n * @param {Array} params\n * @return {String} encoded list of params\n */\nSolidityCoder.prototype.encodeParams = function (types, params) {\n var self = this;\n var solidityParams = types.map(function (type, index) {\n return self._formatInput(type, params[index]);\n });\n\n return SolidityParam.encodeList(solidityParams);\n};\n\n/**\n * Should be used to decode bytes to plain param\n *\n * @method decodeParam\n * @param {String} type\n * @param {String} bytes\n * @return {Object} plain param\n */\nSolidityCoder.prototype.decodeParam = function (type, bytes) {\n return this.decodeParams([type], bytes)[0];\n};\n\n/**\n * Should be used to decode list of params\n *\n * @method decodeParam\n * @param {Array} types\n * @param {String} bytes\n * @return {Array} array of plain params\n */\nSolidityCoder.prototype.decodeParams = function (types, bytes) {\n var self = this;\n return types.map(function (type, index) {\n var solidityType = self._requireType(type);\n var p = solidityType.sliceParam(bytes, index, type);\n return solidityType.formatOutput(p, isArrayType(type));\n });\n};\n\nvar coder = new SolidityCoder([\n new SolidityType({\n name: 'address',\n match: 'strict',\n mode: 'value',\n inputFormatter: f.formatInputInt,\n outputFormatter: f.formatOutputAddress\n }),\n new SolidityType({\n name: 'bool',\n match: 'strict',\n mode: 'value',\n inputFormatter: f.formatInputBool,\n outputFormatter: f.formatOutputBool\n }),\n new SolidityType({\n name: 'int',\n match: 'prefix',\n mode: 'value',\n inputFormatter: f.formatInputInt,\n outputFormatter: f.formatOutputInt,\n }),\n new SolidityType({\n name: 'uint',\n match: 'prefix',\n mode: 'value',\n inputFormatter: f.formatInputInt,\n outputFormatter: f.formatOutputUInt\n }),\n new SolidityType({\n name: 'bytes',\n match: 'strict',\n mode: 'bytes',\n inputFormatter: f.formatInputDynamicBytes,\n outputFormatter: f.formatOutputDynamicBytes\n }),\n new SolidityType({\n name: 'bytes',\n match: 'prefix',\n mode: 'value',\n inputFormatter: f.formatInputBytes,\n outputFormatter: f.formatOutputBytes\n }),\n new SolidityType({\n name: 'real',\n match: 'prefix',\n mode: 'value',\n inputFormatter: f.formatInputReal,\n outputFormatter: f.formatOutputReal\n }),\n new SolidityType({\n name: 'ureal',\n match: 'prefix',\n mode: 'value',\n inputFormatter: f.formatInputReal,\n outputFormatter: f.formatOutputUReal\n })\n]);\n\nmodule.exports = coder;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file formatters.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar BigNumber = require('bignumber.js');\nvar utils = require('../utils/utils');\nvar c = require('../utils/config');\nvar SolidityParam = require('./param');\n\n\n/**\n * Formats input value to byte representation of int\n * If value is negative, return it's two's complement\n * If the value is floating point, round it down\n *\n * @method formatInputInt\n * @param {String|Number|BigNumber} value that needs to be formatted\n * @returns {SolidityParam}\n */\nvar formatInputInt = function (value) {\n var padding = c.ETH_PADDING * 2;\n BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE);\n var result = utils.padLeft(utils.toTwosComplement(value).round().toString(16), padding);\n return new SolidityParam(result);\n};\n\n/**\n * Formats input value to byte representation of string\n *\n * @method formatInputBytes\n * @param {String}\n * @returns {SolidityParam}\n */\nvar formatInputBytes = function (value) {\n var result = utils.fromAscii(value, c.ETH_PADDING).substr(2);\n return new SolidityParam(result);\n};\n\n/**\n * Formats input value to byte representation of string\n *\n * @method formatInputDynamicBytes\n * @param {String}\n * @returns {SolidityParam}\n */\nvar formatInputDynamicBytes = function (value) {\n var result = utils.fromAscii(value, c.ETH_PADDING).substr(2);\n return new SolidityParam(formatInputInt(value.length).value + result, 32);\n};\n\n/**\n * Formats input value to byte representation of bool\n *\n * @method formatInputBool\n * @param {Boolean}\n * @returns {SolidityParam}\n */\nvar formatInputBool = function (value) {\n var result = '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0');\n return new SolidityParam(result);\n};\n\n/**\n * Formats input value to byte representation of real\n * Values are multiplied by 2^m and encoded as integers\n *\n * @method formatInputReal\n * @param {String|Number|BigNumber}\n * @returns {SolidityParam}\n */\nvar formatInputReal = function (value) {\n return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128)));\n};\n\n/**\n * Check if input value is negative\n *\n * @method signedIsNegative\n * @param {String} value is hex format\n * @returns {Boolean} true if it is negative, otherwise false\n */\nvar signedIsNegative = function (value) {\n return (new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1';\n};\n\n/**\n * Formats right-aligned output bytes to int\n *\n * @method formatOutputInt\n * @param {SolidityParam} param\n * @returns {BigNumber} right-aligned output bytes formatted to big number\n */\nvar formatOutputInt = function (param) {\n var value = param.staticPart() || \"0\";\n\n // check if it's negative number\n // it it is, return two's complement\n if (signedIsNegative(value)) {\n return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1);\n }\n return new BigNumber(value, 16);\n};\n\n/**\n * Formats right-aligned output bytes to uint\n *\n * @method formatOutputUInt\n * @param {SolidityParam}\n * @returns {BigNumeber} right-aligned output bytes formatted to uint\n */\nvar formatOutputUInt = function (param) {\n var value = param.staticPart() || \"0\";\n return new BigNumber(value, 16);\n};\n\n/**\n * Formats right-aligned output bytes to real\n *\n * @method formatOutputReal\n * @param {SolidityParam}\n * @returns {BigNumber} input bytes formatted to real\n */\nvar formatOutputReal = function (param) {\n return formatOutputInt(param).dividedBy(new BigNumber(2).pow(128)); \n};\n\n/**\n * Formats right-aligned output bytes to ureal\n *\n * @method formatOutputUReal\n * @param {SolidityParam}\n * @returns {BigNumber} input bytes formatted to ureal\n */\nvar formatOutputUReal = function (param) {\n return formatOutputUInt(param).dividedBy(new BigNumber(2).pow(128)); \n};\n\n/**\n * Should be used to format output bool\n *\n * @method formatOutputBool\n * @param {SolidityParam}\n * @returns {Boolean} right-aligned input bytes formatted to bool\n */\nvar formatOutputBool = function (param) {\n return param.staticPart() === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false;\n};\n\n/**\n * Should be used to format output string\n *\n * @method formatOutputBytes\n * @param {SolidityParam} left-aligned hex representation of string\n * @returns {String} ascii string\n */\nvar formatOutputBytes = function (param) {\n // length might also be important!\n return utils.toAscii(param.staticPart());\n};\n\n/**\n * Should be used to format output string\n *\n * @method formatOutputDynamicBytes\n * @param {SolidityParam} left-aligned hex representation of string\n * @returns {String} ascii string\n */\nvar formatOutputDynamicBytes = function (param) {\n // length might also be important!\n return utils.toAscii(param.dynamicPart().slice(64));\n};\n\n/**\n * Should be used to format output address\n *\n * @method formatOutputAddress\n * @param {SolidityParam} right-aligned input bytes\n * @returns {String} address\n */\nvar formatOutputAddress = function (param) {\n var value = param.staticPart();\n return \"0x\" + value.slice(value.length - 40, value.length);\n};\n\nmodule.exports = {\n formatInputInt: formatInputInt,\n formatInputBytes: formatInputBytes,\n formatInputDynamicBytes: formatInputDynamicBytes,\n formatInputBool: formatInputBool,\n formatInputReal: formatInputReal,\n formatOutputInt: formatOutputInt,\n formatOutputUInt: formatOutputUInt,\n formatOutputReal: formatOutputReal,\n formatOutputUReal: formatOutputUReal,\n formatOutputBool: formatOutputBool,\n formatOutputBytes: formatOutputBytes,\n formatOutputDynamicBytes: formatOutputDynamicBytes,\n formatOutputAddress: formatOutputAddress\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file param.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar utils = require('../utils/utils');\n\n/**\n * SolidityParam object prototype.\n * Should be used when encoding, decoding solidity bytes\n */\nvar SolidityParam = function (value, offset) {\n this.value = value || '';\n this.offset = offset; // offset in bytes\n};\n\n/**\n * This method should be used to get length of params's dynamic part\n * \n * @method dynamicPartLength\n * @returns {Number} length of dynamic part (in bytes)\n */\nSolidityParam.prototype.dynamicPartLength = function () {\n return this.dynamicPart().length / 2;\n};\n\n/**\n * This method should be used to create copy of solidity param with different offset\n *\n * @method withOffset\n * @param {Number} offset length in bytes\n * @returns {SolidityParam} new solidity param with applied offset\n */\nSolidityParam.prototype.withOffset = function (offset) {\n return new SolidityParam(this.value, offset);\n};\n\n/**\n * This method should be used to combine solidity params together\n * eg. when appending an array\n *\n * @method combine\n * @param {SolidityParam} param with which we should combine\n * @param {SolidityParam} result of combination\n */\nSolidityParam.prototype.combine = function (param) {\n return new SolidityParam(this.value + param.value); \n};\n\n/**\n * This method should be called to check if param has dynamic size.\n * If it has, it returns true, otherwise false\n *\n * @method isDynamic\n * @returns {Boolean}\n */\nSolidityParam.prototype.isDynamic = function () {\n return this.value.length > 64;\n};\n\n/**\n * This method should be called to transform offset to bytes\n *\n * @method offsetAsBytes\n * @returns {String} bytes representation of offset\n */\nSolidityParam.prototype.offsetAsBytes = function () {\n return !this.isDynamic() ? '' : utils.padLeft(utils.toTwosComplement(this.offset).toString(16), 64);\n};\n\n/**\n * This method should be called to get static part of param\n *\n * @method staticPart\n * @returns {String} offset if it is a dynamic param, otherwise value\n */\nSolidityParam.prototype.staticPart = function () {\n if (!this.isDynamic()) {\n return this.value; \n } \n return this.offsetAsBytes();\n};\n\n/**\n * This method should be called to get dynamic part of param\n *\n * @method dynamicPart\n * @returns {String} returns a value if it is a dynamic param, otherwise empty string\n */\nSolidityParam.prototype.dynamicPart = function () {\n return this.isDynamic() ? this.value : '';\n};\n\n/**\n * This method should be called to encode param\n *\n * @method encode\n * @returns {String}\n */\nSolidityParam.prototype.encode = function () {\n return this.staticPart() + this.dynamicPart();\n};\n\n/**\n * This method should be called to encode array of params\n *\n * @method encodeList\n * @param {Array[SolidityParam]} params\n * @returns {String}\n */\nSolidityParam.encodeList = function (params) {\n \n // updating offsets\n var totalOffset = params.length * 32;\n var offsetParams = params.map(function (param) {\n if (!param.isDynamic()) {\n return param;\n }\n var offset = totalOffset;\n totalOffset += param.dynamicPartLength();\n return param.withOffset(offset);\n });\n\n // encode everything!\n return offsetParams.reduce(function (result, param) {\n return result + param.dynamicPart();\n }, offsetParams.reduce(function (result, param) {\n return result + param.staticPart();\n }, ''));\n};\n\n/**\n * This method should be used to decode plain (static) solidity param at given index\n *\n * @method decodeParam\n * @param {String} bytes\n * @param {Number} index\n * @returns {SolidityParam}\n */\nSolidityParam.decodeParam = function (bytes, index) {\n index = index || 0;\n return new SolidityParam(bytes.substr(index * 64, 64)); \n};\n\n/**\n * This method should be called to get offset value from bytes at given index\n *\n * @method getOffset\n * @param {String} bytes\n * @param {Number} index\n * @returns {Number} offset as number\n */\nvar getOffset = function (bytes, index) {\n // we can do this cause offset is rather small\n return parseInt('0x' + bytes.substr(index * 64, 64));\n};\n\n/**\n * This method should be called to decode solidity bytes param at given index\n *\n * @method decodeBytes\n * @param {String} bytes\n * @param {Number} index\n * @returns {SolidityParam}\n */\nSolidityParam.decodeBytes = function (bytes, index) {\n index = index || 0;\n //TODO add support for strings longer than 32 bytes\n //var length = parseInt('0x' + bytes.substr(offset * 64, 64));\n\n var offset = getOffset(bytes, index);\n\n // 2 * , cause we also parse length\n return new SolidityParam(bytes.substr(offset * 2, 2 * 64));\n};\n\n/**\n * This method should be used to decode solidity array at given index\n *\n * @method decodeArray\n * @param {String} bytes\n * @param {Number} index\n * @returns {SolidityParam}\n */\nSolidityParam.decodeArray = function (bytes, index) {\n index = index || 0;\n var offset = getOffset(bytes, index);\n var length = parseInt('0x' + bytes.substr(offset * 2, 64));\n return new SolidityParam(bytes.substr(offset * 2, (length + 1) * 64));\n};\n\nmodule.exports = SolidityParam;\n\n", - "'use strict';\n\n// go env doesn't have and need XMLHttpRequest\nif (typeof XMLHttpRequest === 'undefined') {\n exports.XMLHttpRequest = {};\n} else {\n exports.XMLHttpRequest = XMLHttpRequest; // jshint ignore:line\n}\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file config.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\n/**\n * Utils\n * \n * @module utils\n */\n\n/**\n * Utility functions\n * \n * @class [utils] config\n * @constructor\n */\n\n/// required to define ETH_BIGNUMBER_ROUNDING_MODE\nvar BigNumber = require('bignumber.js');\n\nvar ETH_UNITS = [ \n 'wei', \n 'Kwei', \n 'Mwei', \n 'Gwei', \n 'szabo', \n 'finney', \n 'ether', \n 'grand', \n 'Mether', \n 'Gether', \n 'Tether', \n 'Pether', \n 'Eether', \n 'Zether', \n 'Yether', \n 'Nether', \n 'Dether', \n 'Vether', \n 'Uether' \n];\n\nmodule.exports = {\n ETH_PADDING: 32,\n ETH_SIGNATURE_LENGTH: 4,\n ETH_UNITS: ETH_UNITS,\n ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN },\n ETH_POLLING_TIMEOUT: 1000,\n defaultBlock: 'latest',\n defaultAccount: undefined\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file utils.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\n/**\n * Utils\n * \n * @module utils\n */\n\n/**\n * Utility functions\n * \n * @class [utils] utils\n * @constructor\n */\n\nvar BigNumber = require('bignumber.js');\n\nvar unitMap = {\n 'wei': '1',\n 'kwei': '1000',\n 'ada': '1000',\n 'mwei': '1000000',\n 'babbage': '1000000',\n 'gwei': '1000000000',\n 'shannon': '1000000000',\n 'szabo': '1000000000000',\n 'finney': '1000000000000000',\n 'ether': '1000000000000000000',\n 'kether': '1000000000000000000000',\n 'grand': '1000000000000000000000',\n 'einstein': '1000000000000000000000',\n 'mether': '1000000000000000000000000',\n 'gether': '1000000000000000000000000000',\n 'tether': '1000000000000000000000000000000'\n};\n\n/**\n * Should be called to pad string to expected length\n *\n * @method padLeft\n * @param {String} string to be padded\n * @param {Number} characters that result string should have\n * @param {String} sign, by default 0\n * @returns {String} right aligned string\n */\nvar padLeft = function (string, chars, sign) {\n return new Array(chars - string.length + 1).join(sign ? sign : \"0\") + string;\n};\n\n/** \n * Should be called to get sting from it's hex representation\n *\n * @method toAscii\n * @param {String} string in hex\n * @returns {String} ascii string representation of hex value\n */\nvar toAscii = function(hex) {\n// Find termination\n var str = \"\";\n var i = 0, l = hex.length;\n if (hex.substring(0, 2) === '0x') {\n i = 2;\n }\n for (; i < l; i+=2) {\n var code = parseInt(hex.substr(i, 2), 16);\n if (code === 0) {\n break;\n }\n\n str += String.fromCharCode(code);\n }\n\n return str;\n};\n \n/**\n * Shold be called to get hex representation (prefixed by 0x) of ascii string \n *\n * @method toHexNative\n * @param {String} string\n * @returns {String} hex representation of input string\n */\nvar toHexNative = function(str) {\n var hex = \"\";\n for(var i = 0; i < str.length; i++) {\n var n = str.charCodeAt(i).toString(16);\n hex += n.length < 2 ? '0' + n : n;\n }\n\n return hex;\n};\n\n/**\n * Shold be called to get hex representation (prefixed by 0x) of ascii string \n *\n * @method fromAscii\n * @param {String} string\n * @param {Number} optional padding\n * @returns {String} hex representation of input string\n */\nvar fromAscii = function(str, pad) {\n pad = pad === undefined ? 0 : pad;\n var hex = toHexNative(str);\n while (hex.length < pad*2)\n hex += \"00\";\n return \"0x\" + hex;\n};\n\n/**\n * Should be used to create full function/event name from json abi\n *\n * @method transformToFullName\n * @param {Object} json-abi\n * @return {String} full fnction/event name\n */\nvar transformToFullName = function (json) {\n if (json.name.indexOf('(') !== -1) {\n return json.name;\n }\n\n var typeName = json.inputs.map(function(i){return i.type; }).join();\n return json.name + '(' + typeName + ')';\n};\n\n/**\n * Should be called to get display name of contract function\n * \n * @method extractDisplayName\n * @param {String} name of function/event\n * @returns {String} display name for function/event eg. multiply(uint256) -> multiply\n */\nvar extractDisplayName = function (name) {\n var length = name.indexOf('('); \n return length !== -1 ? name.substr(0, length) : name;\n};\n\n/// @returns overloaded part of function/event name\nvar extractTypeName = function (name) {\n /// TODO: make it invulnerable\n var length = name.indexOf('(');\n return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : \"\";\n};\n\n/**\n * Converts value to it's decimal representation in string\n *\n * @method toDecimal\n * @param {String|Number|BigNumber}\n * @return {String}\n */\nvar toDecimal = function (value) {\n return toBigNumber(value).toNumber();\n};\n\n/**\n * Converts value to it's hex representation\n *\n * @method fromDecimal\n * @param {String|Number|BigNumber}\n * @return {String}\n */\nvar fromDecimal = function (value) {\n var number = toBigNumber(value);\n var result = number.toString(16);\n\n return number.lessThan(0) ? '-0x' + result.substr(1) : '0x' + result;\n};\n\n/**\n * Auto converts any given value into it's hex representation.\n *\n * And even stringifys objects before.\n *\n * @method toHex\n * @param {String|Number|BigNumber|Object}\n * @return {String}\n */\nvar toHex = function (val) {\n /*jshint maxcomplexity:7 */\n\n if (isBoolean(val))\n return fromDecimal(+val);\n\n if (isBigNumber(val))\n return fromDecimal(val);\n\n if (isObject(val))\n return fromAscii(JSON.stringify(val));\n\n // if its a negative number, pass it through fromDecimal\n if (isString(val)) {\n if (val.indexOf('-0x') === 0)\n return fromDecimal(val);\n else if (!isFinite(val))\n return fromAscii(val);\n }\n\n return fromDecimal(val);\n};\n\n/**\n * Returns value of unit in Wei\n *\n * @method getValueOfUnit\n * @param {String} unit the unit to convert to, default ether\n * @returns {BigNumber} value of the unit (in Wei)\n * @throws error if the unit is not correct:w\n */\nvar getValueOfUnit = function (unit) {\n unit = unit ? unit.toLowerCase() : 'ether';\n var unitValue = unitMap[unit];\n if (unitValue === undefined) {\n throw new Error('This unit doesn\\'t exists, please use the one of the following units' + JSON.stringify(unitMap, null, 2));\n }\n return new BigNumber(unitValue, 10);\n};\n\n/**\n * Takes a number of wei and converts it to any other ether unit.\n *\n * Possible units are:\n * - kwei/ada\n * - mwei/babbage\n * - gwei/shannon\n * - szabo\n * - finney\n * - ether\n * - kether/grand/einstein\n * - mether\n * - gether\n * - tether\n *\n * @method fromWei\n * @param {Number|String} number can be a number, number string or a HEX of a decimal\n * @param {String} unit the unit to convert to, default ether\n * @return {String|Object} When given a BigNumber object it returns one as well, otherwise a number\n*/\nvar fromWei = function(number, unit) {\n var returnValue = toBigNumber(number).dividedBy(getValueOfUnit(unit));\n\n return isBigNumber(number) ? returnValue : returnValue.toString(10); \n};\n\n/**\n * Takes a number of a unit and converts it to wei.\n *\n * Possible units are:\n * - kwei/ada\n * - mwei/babbage\n * - gwei/shannon\n * - szabo\n * - finney\n * - ether\n * - kether/grand/einstein\n * - mether\n * - gether\n * - tether\n *\n * @method toWei\n * @param {Number|String|BigNumber} number can be a number, number string or a HEX of a decimal\n * @param {String} unit the unit to convert from, default ether\n * @return {String|Object} When given a BigNumber object it returns one as well, otherwise a number\n*/\nvar toWei = function(number, unit) {\n var returnValue = toBigNumber(number).times(getValueOfUnit(unit));\n\n return isBigNumber(number) ? returnValue : returnValue.toString(10); \n};\n\n/**\n * Takes an input and transforms it into an bignumber\n *\n * @method toBigNumber\n * @param {Number|String|BigNumber} a number, string, HEX string or BigNumber\n * @return {BigNumber} BigNumber\n*/\nvar toBigNumber = function(number) {\n /*jshint maxcomplexity:5 */\n number = number || 0;\n if (isBigNumber(number))\n return number;\n\n if (isString(number) && (number.indexOf('0x') === 0 || number.indexOf('-0x') === 0)) {\n return new BigNumber(number.replace('0x',''), 16);\n }\n \n return new BigNumber(number.toString(10), 10);\n};\n\n/**\n * Takes and input transforms it into bignumber and if it is negative value, into two's complement\n *\n * @method toTwosComplement\n * @param {Number|String|BigNumber}\n * @return {BigNumber}\n */\nvar toTwosComplement = function (number) {\n var bigNumber = toBigNumber(number);\n if (bigNumber.lessThan(0)) {\n return new BigNumber(\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\", 16).plus(bigNumber).plus(1);\n }\n return bigNumber;\n};\n\n/**\n * Checks if the given string is strictly an address\n *\n * @method isStrictAddress\n * @param {String} address the given HEX adress\n * @return {Boolean}\n*/\nvar isStrictAddress = function (address) {\n return /^0x[0-9a-f]{40}$/.test(address);\n};\n\n/**\n * Checks if the given string is an address\n *\n * @method isAddress\n * @param {String} address the given HEX adress\n * @return {Boolean}\n*/\nvar isAddress = function (address) {\n return /^(0x)?[0-9a-f]{40}$/.test(address);\n};\n\n/**\n * Transforms given string to valid 20 bytes-length addres with 0x prefix\n *\n * @method toAddress\n * @param {String} address\n * @return {String} formatted address\n */\nvar toAddress = function (address) {\n if (isStrictAddress(address)) {\n return address;\n }\n \n if (/^[0-9a-f]{40}$/.test(address)) {\n return '0x' + address;\n }\n\n return '0x' + padLeft(toHex(address).substr(2), 40);\n};\n\n\n/**\n * Returns true if object is BigNumber, otherwise false\n *\n * @method isBigNumber\n * @param {Object}\n * @return {Boolean} \n */\nvar isBigNumber = function (object) {\n return object instanceof BigNumber ||\n (object && object.constructor && object.constructor.name === 'BigNumber');\n};\n\n/**\n * Returns true if object is string, otherwise false\n * \n * @method isString\n * @param {Object}\n * @return {Boolean}\n */\nvar isString = function (object) {\n return typeof object === 'string' ||\n (object && object.constructor && object.constructor.name === 'String');\n};\n\n/**\n * Returns true if object is function, otherwise false\n *\n * @method isFunction\n * @param {Object}\n * @return {Boolean}\n */\nvar isFunction = function (object) {\n return typeof object === 'function';\n};\n\n/**\n * Returns true if object is Objet, otherwise false\n *\n * @method isObject\n * @param {Object}\n * @return {Boolean}\n */\nvar isObject = function (object) {\n return typeof object === 'object';\n};\n\n/**\n * Returns true if object is boolean, otherwise false\n *\n * @method isBoolean\n * @param {Object}\n * @return {Boolean}\n */\nvar isBoolean = function (object) {\n return typeof object === 'boolean';\n};\n\n/**\n * Returns true if object is array, otherwise false\n *\n * @method isArray\n * @param {Object}\n * @return {Boolean}\n */\nvar isArray = function (object) {\n return object instanceof Array; \n};\n\n/**\n * Returns true if given string is valid json object\n * \n * @method isJson\n * @param {String}\n * @return {Boolean}\n */\nvar isJson = function (str) {\n try {\n return !!JSON.parse(str);\n } catch (e) {\n return false;\n }\n};\n\nmodule.exports = {\n padLeft: padLeft,\n toHex: toHex,\n toDecimal: toDecimal,\n fromDecimal: fromDecimal,\n toAscii: toAscii,\n fromAscii: fromAscii,\n transformToFullName: transformToFullName,\n extractDisplayName: extractDisplayName,\n extractTypeName: extractTypeName,\n toWei: toWei,\n fromWei: fromWei,\n toBigNumber: toBigNumber,\n toTwosComplement: toTwosComplement,\n toAddress: toAddress,\n isBigNumber: isBigNumber,\n isStrictAddress: isStrictAddress,\n isAddress: isAddress,\n isFunction: isFunction,\n isString: isString,\n isObject: isObject,\n isBoolean: isBoolean,\n isArray: isArray,\n isJson: isJson\n};\n\n", - "module.exports={\n \"version\": \"0.4.2\"\n}\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file web3.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Fabian Vogelsteller \n * Gav Wood \n * @date 2014\n */\n\nvar version = require('./version.json');\nvar net = require('./web3/net');\nvar eth = require('./web3/eth');\nvar db = require('./web3/db');\nvar shh = require('./web3/shh');\nvar watches = require('./web3/watches');\nvar Filter = require('./web3/filter');\nvar utils = require('./utils/utils');\nvar formatters = require('./web3/formatters');\nvar RequestManager = require('./web3/requestmanager');\nvar c = require('./utils/config');\nvar Method = require('./web3/method');\nvar Property = require('./web3/property');\nvar Batch = require('./web3/batch');\n\nvar web3Methods = [\n new Method({\n name: 'sha3',\n call: 'web3_sha3',\n params: 1\n })\n];\n\nvar web3Properties = [\n new Property({\n name: 'version.client',\n getter: 'web3_clientVersion'\n }),\n new Property({\n name: 'version.network',\n getter: 'net_version',\n inputFormatter: utils.toDecimal\n }),\n new Property({\n name: 'version.ethereum',\n getter: 'eth_protocolVersion',\n inputFormatter: utils.toDecimal\n }),\n new Property({\n name: 'version.whisper',\n getter: 'shh_version',\n inputFormatter: utils.toDecimal\n })\n];\n\n/// creates methods in a given object based on method description on input\n/// setups api calls for these methods\nvar setupMethods = function (obj, methods) {\n methods.forEach(function (method) {\n method.attachToObject(obj);\n });\n};\n\n/// creates properties in a given object based on properties description on input\n/// setups api calls for these properties\nvar setupProperties = function (obj, properties) {\n properties.forEach(function (property) {\n property.attachToObject(obj);\n });\n};\n\n/// setups web3 object, and it's in-browser executed methods\nvar web3 = {};\nweb3.providers = {};\nweb3.version = {};\nweb3.version.api = version.version;\nweb3.eth = {};\n\n/*jshint maxparams:4 */\nweb3.eth.filter = function (fil, eventParams, options, formatter) {\n\n // if its event, treat it differently\n // TODO: simplify and remove\n if (fil._isEvent) {\n return fil(eventParams, options);\n }\n\n // what outputLogFormatter? that's wrong\n //return new Filter(fil, watches.eth(), formatters.outputLogFormatter);\n return new Filter(fil, watches.eth(), formatter || formatters.outputLogFormatter);\n};\n/*jshint maxparams:3 */\n\nweb3.shh = {};\nweb3.shh.filter = function (fil) {\n return new Filter(fil, watches.shh(), formatters.outputPostFormatter);\n};\nweb3.net = {};\nweb3.db = {};\nweb3.setProvider = function (provider) {\n RequestManager.getInstance().setProvider(provider);\n};\nweb3.reset = function () {\n RequestManager.getInstance().reset();\n c.defaultBlock = 'latest';\n c.defaultAccount = undefined;\n};\nweb3.toHex = utils.toHex;\nweb3.toAscii = utils.toAscii;\nweb3.fromAscii = utils.fromAscii;\nweb3.toDecimal = utils.toDecimal;\nweb3.fromDecimal = utils.fromDecimal;\nweb3.toBigNumber = utils.toBigNumber;\nweb3.toWei = utils.toWei;\nweb3.fromWei = utils.fromWei;\nweb3.isAddress = utils.isAddress;\nweb3.createBatch = function () {\n return new Batch();\n};\n\n// ADD defaultblock\nObject.defineProperty(web3.eth, 'defaultBlock', {\n get: function () {\n return c.defaultBlock;\n },\n set: function (val) {\n c.defaultBlock = val;\n return val;\n }\n});\n\nObject.defineProperty(web3.eth, 'defaultAccount', {\n get: function () {\n return c.defaultAccount;\n },\n set: function (val) {\n c.defaultAccount = val;\n return val;\n }\n});\n\n/// setups all api methods\nsetupMethods(web3, web3Methods);\nsetupProperties(web3, web3Properties);\nsetupMethods(web3.net, net.methods);\nsetupProperties(web3.net, net.properties);\nsetupMethods(web3.eth, eth.methods);\nsetupProperties(web3.eth, eth.properties);\nsetupMethods(web3.db, db.methods);\nsetupMethods(web3.shh, shh.methods);\n\nmodule.exports = web3;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file batch.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar RequestManager = require('./requestmanager');\n\nvar Batch = function () {\n this.requests = [];\n};\n\n/**\n * Should be called to add create new request to batch request\n *\n * @method add\n * @param {Object} jsonrpc requet object\n */\nBatch.prototype.add = function (request) {\n this.requests.push(request);\n};\n\n/**\n * Should be called to execute batch request\n *\n * @method execute\n */\nBatch.prototype.execute = function () {\n var requests = this.requests;\n RequestManager.getInstance().sendBatch(requests, function (err, results) {\n results = results || [];\n requests.map(function (request, index) {\n return results[index] || {};\n }).map(function (result, index) {\n return requests[index].format ? requests[index].format(result.result) : result.result;\n }).forEach(function (result, index) {\n if (requests[index].callback) {\n requests[index].callback(err, result);\n }\n });\n }); \n};\n\nmodule.exports = Batch;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file contract.js\n * @author Marek Kotewicz \n * @date 2014\n */\n\nvar web3 = require('../web3'); \nvar utils = require('../utils/utils');\nvar coder = require('../solidity/coder');\nvar SolidityEvent = require('./event');\nvar SolidityFunction = require('./function');\n\n/**\n * Should be called to encode constructor params\n *\n * @method encodeConstructorParams\n * @param {Array} abi\n * @param {Array} constructor params\n */\nvar encodeConstructorParams = function (abi, params) {\n return abi.filter(function (json) {\n return json.type === 'constructor' && json.inputs.length === params.length;\n }).map(function (json) {\n return json.inputs.map(function (input) {\n return input.type;\n });\n }).map(function (types) {\n return coder.encodeParams(types, params);\n })[0] || '';\n};\n\n/**\n * Should be called to add functions to contract object\n *\n * @method addFunctionsToContract\n * @param {Contract} contract\n * @param {Array} abi\n */\nvar addFunctionsToContract = function (contract, abi) {\n abi.filter(function (json) {\n return json.type === 'function';\n }).map(function (json) {\n return new SolidityFunction(json, contract.address);\n }).forEach(function (f) {\n f.attachToContract(contract);\n });\n};\n\n/**\n * Should be called to add events to contract object\n *\n * @method addEventsToContract\n * @param {Contract} contract\n * @param {Array} abi\n */\nvar addEventsToContract = function (contract, abi) {\n abi.filter(function (json) {\n return json.type === 'event';\n }).map(function (json) {\n return new SolidityEvent(json, contract.address);\n }).forEach(function (e) {\n e.attachToContract(contract);\n });\n};\n\n/**\n * Should be called to create new ContractFactory\n *\n * @method contract\n * @param {Array} abi\n * @returns {ContractFactory} new contract factory\n */\nvar contract = function (abi) {\n return new ContractFactory(abi);\n};\n\n/**\n * Should be called to create new ContractFactory instance\n *\n * @method ContractFactory\n * @param {Array} abi\n */\nvar ContractFactory = function (abi) {\n this.abi = abi;\n};\n\n/**\n * Should be called to create new contract on a blockchain\n * \n * @method new\n * @param {Any} contract constructor param1 (optional)\n * @param {Any} contract constructor param2 (optional)\n * @param {Object} contract transaction object (required)\n * @param {Function} callback\n * @returns {Contract} returns contract if no callback was passed,\n * otherwise calls callback function (err, contract)\n */\nContractFactory.prototype.new = function () {\n // parse arguments\n var options = {}; // required!\n var callback;\n\n var args = Array.prototype.slice.call(arguments);\n if (utils.isFunction(args[args.length - 1])) {\n callback = args.pop();\n }\n\n var last = args[args.length - 1];\n if (utils.isObject(last) && !utils.isArray(last)) {\n options = args.pop();\n }\n\n // throw an error if there are no options\n\n var bytes = encodeConstructorParams(this.abi, args);\n options.data += bytes;\n\n if (!callback) {\n var address = web3.eth.sendTransaction(options);\n return this.at(address);\n }\n \n var self = this;\n web3.eth.sendTransaction(options, function (err, address) {\n if (err) {\n callback(err);\n }\n self.at(address, callback); \n }); \n};\n\n/**\n * Should be called to get access to existing contract on a blockchain\n *\n * @method at\n * @param {Address} contract address (required)\n * @param {Function} callback {optional)\n * @returns {Contract} returns contract if no callback was passed,\n * otherwise calls callback function (err, contract)\n */\nContractFactory.prototype.at = function (address, callback) {\n // TODO: address is required\n \n if (callback) {\n callback(null, new Contract(this.abi, address));\n } \n return new Contract(this.abi, address);\n};\n\n/**\n * Should be called to create new contract instance\n *\n * @method Contract\n * @param {Array} abi\n * @param {Address} contract address\n */\nvar Contract = function (abi, address) {\n this.address = address;\n addFunctionsToContract(this, abi);\n addEventsToContract(this, abi);\n};\n\nmodule.exports = contract;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file db.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar Method = require('./method');\n\nvar putString = new Method({\n name: 'putString',\n call: 'db_putString',\n params: 3\n});\n\n\nvar getString = new Method({\n name: 'getString',\n call: 'db_getString',\n params: 2\n});\n\nvar putHex = new Method({\n name: 'putHex',\n call: 'db_putHex',\n params: 3\n});\n\nvar getHex = new Method({\n name: 'getHex',\n call: 'db_getHex',\n params: 2\n});\n\nvar methods = [\n putString, getString, putHex, getHex\n];\n\nmodule.exports = {\n methods: methods\n};\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file errors.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nmodule.exports = {\n InvalidNumberOfParams: function () {\n return new Error('Invalid number of input parameters');\n },\n InvalidConnection: function (host){\n return new Error('CONNECTION ERROR: Couldn\\'t connect to node '+ host +', is it running?');\n },\n InvalidProvider: function () {\n return new Error('Providor not set or invalid');\n },\n InvalidResponse: function (result){\n var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response';\n return new Error(message);\n }\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file eth.js\n * @author Marek Kotewicz \n * @author Fabian Vogelsteller \n * @date 2015\n */\n\n/**\n * Web3\n *\n * @module web3\n */\n\n/**\n * Eth methods and properties\n *\n * An example method object can look as follows:\n *\n * {\n * name: 'getBlock',\n * call: blockCall,\n * params: 2,\n * outputFormatter: formatters.outputBlockFormatter,\n * inputFormatter: [ // can be a formatter funciton or an array of functions. Where each item in the array will be used for one parameter\n * utils.toHex, // formats paramter 1\n * function(param){ return !!param; } // formats paramter 2\n * ]\n * },\n *\n * @class [web3] eth\n * @constructor\n */\n\n\"use strict\";\n\nvar formatters = require('./formatters');\nvar utils = require('../utils/utils');\nvar Method = require('./method');\nvar Property = require('./property');\n\nvar blockCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? \"eth_getBlockByHash\" : \"eth_getBlockByNumber\";\n};\n\nvar transactionFromBlockCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getTransactionByBlockHashAndIndex' : 'eth_getTransactionByBlockNumberAndIndex';\n};\n\nvar uncleCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleByBlockHashAndIndex' : 'eth_getUncleByBlockNumberAndIndex';\n};\n\nvar getBlockTransactionCountCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getBlockTransactionCountByHash' : 'eth_getBlockTransactionCountByNumber';\n};\n\nvar uncleCountCall = function (args) {\n return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleCountByBlockHash' : 'eth_getUncleCountByBlockNumber';\n};\n\n/// @returns an array of objects describing web3.eth api methods\n\nvar getBalance = new Method({\n name: 'getBalance',\n call: 'eth_getBalance',\n params: 2,\n inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter],\n outputFormatter: formatters.outputBigNumberFormatter\n});\n\nvar getStorageAt = new Method({\n name: 'getStorageAt',\n call: 'eth_getStorageAt',\n params: 3,\n inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar getCode = new Method({\n name: 'getCode',\n call: 'eth_getCode',\n params: 2,\n inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar getBlock = new Method({\n name: 'getBlock',\n call: blockCall,\n params: 2,\n inputFormatter: [formatters.inputBlockNumberFormatter, function (val) { return !!val; }],\n outputFormatter: formatters.outputBlockFormatter\n});\n\nvar getUncle = new Method({\n name: 'getUncle',\n call: uncleCall,\n params: 2,\n inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex],\n outputFormatter: formatters.outputBlockFormatter,\n\n});\n\nvar getCompilers = new Method({\n name: 'getCompilers',\n call: 'eth_getCompilers',\n params: 0\n});\n\nvar getBlockTransactionCount = new Method({\n name: 'getBlockTransactionCount',\n call: getBlockTransactionCountCall,\n params: 1,\n inputFormatter: [formatters.inputBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar getBlockUncleCount = new Method({\n name: 'getBlockUncleCount',\n call: uncleCountCall,\n params: 1,\n inputFormatter: [formatters.inputBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar getTransaction = new Method({\n name: 'getTransaction',\n call: 'eth_getTransactionByHash',\n params: 1,\n outputFormatter: formatters.outputTransactionFormatter\n});\n\nvar getTransactionFromBlock = new Method({\n name: 'getTransactionFromBlock',\n call: transactionFromBlockCall,\n params: 2,\n inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex],\n outputFormatter: formatters.outputTransactionFormatter\n});\n\nvar getTransactionCount = new Method({\n name: 'getTransactionCount',\n call: 'eth_getTransactionCount',\n params: 2,\n inputFormatter: [null, formatters.inputDefaultBlockNumberFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar sendTransaction = new Method({\n name: 'sendTransaction',\n call: 'eth_sendTransaction',\n params: 1,\n inputFormatter: [formatters.inputTransactionFormatter]\n});\n\nvar call = new Method({\n name: 'call',\n call: 'eth_call',\n params: 2,\n inputFormatter: [formatters.inputTransactionFormatter, formatters.inputDefaultBlockNumberFormatter]\n});\n\nvar estimateGas = new Method({\n name: 'estimateGas',\n call: 'eth_estimateGas',\n params: 1,\n inputFormatter: [formatters.inputTransactionFormatter],\n outputFormatter: utils.toDecimal\n});\n\nvar compileSolidity = new Method({\n name: 'compile.solidity',\n call: 'eth_compileSolidity',\n params: 1\n});\n\nvar compileLLL = new Method({\n name: 'compile.lll',\n call: 'eth_compileLLL',\n params: 1\n});\n\nvar compileSerpent = new Method({\n name: 'compile.serpent',\n call: 'eth_compileSerpent',\n params: 1\n});\n\nvar submitWork = new Method({\n name: 'submitWork',\n call: 'eth_submitWork',\n params: 3\n});\n\nvar getWork = new Method({\n name: 'getWork',\n call: 'eth_getWork',\n params: 0\n});\n\nvar methods = [\n getBalance,\n getStorageAt,\n getCode,\n getBlock,\n getUncle,\n getCompilers,\n getBlockTransactionCount,\n getBlockUncleCount,\n getTransaction,\n getTransactionFromBlock,\n getTransactionCount,\n call,\n estimateGas,\n sendTransaction,\n compileSolidity,\n compileLLL,\n compileSerpent,\n submitWork,\n getWork\n];\n\n/// @returns an array of objects describing web3.eth api properties\n\n\n\nvar properties = [\n new Property({\n name: 'coinbase',\n getter: 'eth_coinbase'\n }),\n new Property({\n name: 'mining',\n getter: 'eth_mining'\n }),\n new Property({\n name: 'hashrate',\n getter: 'eth_hashrate',\n outputFormatter: utils.toDecimal\n }),\n new Property({\n name: 'gasPrice',\n getter: 'eth_gasPrice',\n outputFormatter: formatters.outputBigNumberFormatter\n }),\n new Property({\n name: 'accounts',\n getter: 'eth_accounts'\n }),\n new Property({\n name: 'blockNumber',\n getter: 'eth_blockNumber',\n outputFormatter: utils.toDecimal\n })\n];\n\nmodule.exports = {\n methods: methods,\n properties: properties\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file event.js\n * @author Marek Kotewicz \n * @date 2014\n */\n\nvar utils = require('../utils/utils');\nvar coder = require('../solidity/coder');\nvar web3 = require('../web3');\nvar formatters = require('./formatters');\n\n/**\n * This prototype should be used to create event filters\n */\nvar SolidityEvent = function (json, address) {\n this._params = json.inputs;\n this._name = utils.transformToFullName(json);\n this._address = address;\n this._anonymous = json.anonymous;\n};\n\n/**\n * Should be used to get filtered param types\n *\n * @method types\n * @param {Bool} decide if returned typed should be indexed\n * @return {Array} array of types\n */\nSolidityEvent.prototype.types = function (indexed) {\n return this._params.filter(function (i) {\n return i.indexed === indexed;\n }).map(function (i) {\n return i.type;\n });\n};\n\n/**\n * Should be used to get event display name\n *\n * @method displayName\n * @return {String} event display name\n */\nSolidityEvent.prototype.displayName = function () {\n return utils.extractDisplayName(this._name);\n};\n\n/**\n * Should be used to get event type name\n *\n * @method typeName\n * @return {String} event type name\n */\nSolidityEvent.prototype.typeName = function () {\n return utils.extractTypeName(this._name);\n};\n\n/**\n * Should be used to get event signature\n *\n * @method signature\n * @return {String} event signature\n */\nSolidityEvent.prototype.signature = function () {\n return web3.sha3(web3.fromAscii(this._name)).slice(2);\n};\n\n/**\n * Should be used to encode indexed params and options to one final object\n * \n * @method encode\n * @param {Object} indexed\n * @param {Object} options\n * @return {Object} everything combined together and encoded\n */\nSolidityEvent.prototype.encode = function (indexed, options) {\n indexed = indexed || {};\n options = options || {};\n var result = {};\n\n ['fromBlock', 'toBlock'].filter(function (f) {\n return options[f] !== undefined;\n }).forEach(function (f) {\n result[f] = formatters.inputBlockNumberFormatter(options[f]);\n });\n\n result.topics = [];\n\n if (!this._anonymous) {\n result.address = this._address;\n result.topics.push('0x' + this.signature());\n }\n\n var indexedTopics = this._params.filter(function (i) {\n return i.indexed === true;\n }).map(function (i) {\n var value = indexed[i.name];\n if (value === undefined || value === null) {\n return null;\n }\n \n if (utils.isArray(value)) {\n return value.map(function (v) {\n return '0x' + coder.encodeParam(i.type, v);\n });\n }\n return '0x' + coder.encodeParam(i.type, value);\n });\n\n result.topics = result.topics.concat(indexedTopics);\n\n return result;\n};\n\n/**\n * Should be used to decode indexed params and options\n *\n * @method decode\n * @param {Object} data\n * @return {Object} result object with decoded indexed && not indexed params\n */\nSolidityEvent.prototype.decode = function (data) {\n \n data.data = data.data || '';\n data.topics = data.topics || [];\n\n var argTopics = this._anonymous ? data.topics : data.topics.slice(1);\n var indexedData = argTopics.map(function (topics) { return topics.slice(2); }).join(\"\");\n var indexedParams = coder.decodeParams(this.types(true), indexedData); \n\n var notIndexedData = data.data.slice(2);\n var notIndexedParams = coder.decodeParams(this.types(false), notIndexedData);\n \n var result = formatters.outputLogFormatter(data);\n result.event = this.displayName();\n result.address = data.address;\n\n result.args = this._params.reduce(function (acc, current) {\n acc[current.name] = current.indexed ? indexedParams.shift() : notIndexedParams.shift();\n return acc;\n }, {});\n\n delete result.data;\n delete result.topics;\n\n return result;\n};\n\n/**\n * Should be used to create new filter object from event\n *\n * @method execute\n * @param {Object} indexed\n * @param {Object} options\n * @return {Object} filter object\n */\nSolidityEvent.prototype.execute = function (indexed, options) {\n var o = this.encode(indexed, options);\n var formatter = this.decode.bind(this);\n return web3.eth.filter(o, undefined, undefined, formatter);\n};\n\n/**\n * Should be used to attach event to contract object\n *\n * @method attachToContract\n * @param {Contract}\n */\nSolidityEvent.prototype.attachToContract = function (contract) {\n var execute = this.execute.bind(this);\n var displayName = this.displayName();\n if (!contract[displayName]) {\n contract[displayName] = execute;\n }\n contract[displayName][this.typeName()] = this.execute.bind(this, contract);\n};\n\nmodule.exports = SolidityEvent;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file filter.js\n * @authors:\n * Jeffrey Wilcke \n * Marek Kotewicz \n * Marian Oancea \n * Fabian Vogelsteller \n * Gav Wood \n * @date 2014\n */\n\nvar RequestManager = require('./requestmanager');\nvar formatters = require('./formatters');\nvar utils = require('../utils/utils');\n\n/**\n* Converts a given topic to a hex string, but also allows null values.\n*\n* @param {Mixed} value\n* @return {String}\n*/\nvar toTopic = function(value){\n\n if(value === null || typeof value === 'undefined')\n return null;\n\n value = String(value);\n\n if(value.indexOf('0x') === 0)\n return value;\n else\n return utils.fromAscii(value);\n};\n\n/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones\n/// @param should be string or object\n/// @returns options string or object\nvar getOptions = function (options) {\n\n if (utils.isString(options)) {\n return options;\n } \n\n options = options || {};\n\n // make sure topics, get converted to hex\n options.topics = options.topics || [];\n options.topics = options.topics.map(function(topic){\n return (utils.isArray(topic)) ? topic.map(toTopic) : toTopic(topic);\n });\n\n // lazy load\n return {\n topics: options.topics,\n to: options.to,\n address: options.address,\n fromBlock: formatters.inputBlockNumberFormatter(options.fromBlock),\n toBlock: formatters.inputBlockNumberFormatter(options.toBlock) \n }; \n};\n\nvar Filter = function (options, methods, formatter) {\n var implementation = {};\n methods.forEach(function (method) {\n method.attachToObject(implementation);\n });\n this.options = getOptions(options);\n this.implementation = implementation;\n this.callbacks = [];\n this.formatter = formatter;\n this.filterId = this.implementation.newFilter(this.options);\n};\n\nFilter.prototype.watch = function (callback) {\n this.callbacks.push(callback);\n var self = this;\n\n var onMessage = function (error, messages) {\n if (error) {\n return self.callbacks.forEach(function (callback) {\n callback(error);\n });\n }\n\n messages.forEach(function (message) {\n message = self.formatter ? self.formatter(message) : message;\n self.callbacks.forEach(function (callback) {\n callback(null, message);\n });\n });\n };\n\n // call getFilterLogs on start\n if (!utils.isString(this.options)) {\n this.get(function (err, messages) {\n // don't send all the responses to all the watches again... just to this one\n if (err) {\n callback(err);\n }\n\n messages.forEach(function (message) {\n callback(null, message);\n });\n });\n }\n\n RequestManager.getInstance().startPolling({\n method: this.implementation.poll.call,\n params: [this.filterId],\n }, this.filterId, onMessage, this.stopWatching.bind(this));\n};\n\nFilter.prototype.stopWatching = function () {\n RequestManager.getInstance().stopPolling(this.filterId);\n this.implementation.uninstallFilter(this.filterId);\n this.callbacks = [];\n};\n\nFilter.prototype.get = function (callback) {\n var self = this;\n if (utils.isFunction(callback)) {\n this.implementation.getLogs(this.filterId, function(err, res){\n if (err) {\n callback(err);\n } else {\n callback(null, res.map(function (log) {\n return self.formatter ? self.formatter(log) : log;\n }));\n }\n });\n } else {\n var logs = this.implementation.getLogs(this.filterId);\n return logs.map(function (log) {\n return self.formatter ? self.formatter(log) : log;\n });\n }\n};\n\nmodule.exports = Filter;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file formatters.js\n * @author Marek Kotewicz \n * @author Fabian Vogelsteller \n * @date 2015\n */\n\nvar utils = require('../utils/utils');\nvar config = require('../utils/config');\n\n/**\n * Should the format output to a big number\n *\n * @method outputBigNumberFormatter\n * @param {String|Number|BigNumber}\n * @returns {BigNumber} object\n */\nvar outputBigNumberFormatter = function (number) {\n return utils.toBigNumber(number);\n};\n\nvar isPredefinedBlockNumber = function (blockNumber) {\n return blockNumber === 'latest' || blockNumber === 'pending' || blockNumber === 'earliest';\n};\n\nvar inputDefaultBlockNumberFormatter = function (blockNumber) {\n if (blockNumber === undefined) {\n return config.defaultBlock;\n }\n return inputBlockNumberFormatter(blockNumber);\n};\n\nvar inputBlockNumberFormatter = function (blockNumber) {\n if (blockNumber === undefined) {\n return undefined;\n } else if (isPredefinedBlockNumber(blockNumber)) {\n return blockNumber;\n }\n return utils.toHex(blockNumber);\n};\n\n/**\n * Formats the input of a transaction and converts all values to HEX\n *\n * @method inputTransactionFormatter\n * @param {Object} transaction options\n * @returns object\n*/\nvar inputTransactionFormatter = function (options){\n\n options.from = options.from || config.defaultAccount;\n\n // make code -> data\n if (options.code) {\n options.data = options.code;\n delete options.code;\n }\n\n ['gasPrice', 'gas', 'value', 'nonce'].filter(function (key) {\n return options[key] !== undefined;\n }).forEach(function(key){\n options[key] = utils.fromDecimal(options[key]);\n });\n\n return options; \n};\n\n/**\n * Formats the output of a transaction to its proper values\n * \n * @method outputTransactionFormatter\n * @param {Object} transaction\n * @returns {Object} transaction\n*/\nvar outputTransactionFormatter = function (tx){\n tx.blockNumber = utils.toDecimal(tx.blockNumber);\n tx.transactionIndex = utils.toDecimal(tx.transactionIndex);\n tx.nonce = utils.toDecimal(tx.nonce);\n tx.gas = utils.toDecimal(tx.gas);\n tx.gasPrice = utils.toBigNumber(tx.gasPrice);\n tx.value = utils.toBigNumber(tx.value);\n return tx;\n};\n\n/**\n * Formats the output of a block to its proper values\n *\n * @method outputBlockFormatter\n * @param {Object} block object \n * @returns {Object} block object\n*/\nvar outputBlockFormatter = function(block) {\n\n // transform to number\n block.gasLimit = utils.toDecimal(block.gasLimit);\n block.gasUsed = utils.toDecimal(block.gasUsed);\n block.size = utils.toDecimal(block.size);\n block.timestamp = utils.toDecimal(block.timestamp);\n block.number = utils.toDecimal(block.number);\n\n block.difficulty = utils.toBigNumber(block.difficulty);\n block.totalDifficulty = utils.toBigNumber(block.totalDifficulty);\n\n if (utils.isArray(block.transactions)) {\n block.transactions.forEach(function(item){\n if(!utils.isString(item))\n return outputTransactionFormatter(item);\n });\n }\n\n return block;\n};\n\n/**\n * Formats the output of a log\n * \n * @method outputLogFormatter\n * @param {Object} log object\n * @returns {Object} log\n*/\nvar outputLogFormatter = function(log) {\n if (log === null) { // 'pending' && 'latest' filters are nulls\n return null;\n }\n\n log.blockNumber = utils.toDecimal(log.blockNumber);\n log.transactionIndex = utils.toDecimal(log.transactionIndex);\n log.logIndex = utils.toDecimal(log.logIndex);\n\n return log;\n};\n\n/**\n * Formats the input of a whisper post and converts all values to HEX\n *\n * @method inputPostFormatter\n * @param {Object} transaction object\n * @returns {Object}\n*/\nvar inputPostFormatter = function(post) {\n\n post.payload = utils.toHex(post.payload);\n post.ttl = utils.fromDecimal(post.ttl);\n post.workToProve = utils.fromDecimal(post.workToProve);\n post.priority = utils.fromDecimal(post.priority);\n\n // fallback\n if (!utils.isArray(post.topics)) {\n post.topics = post.topics ? [post.topics] : [];\n }\n\n // format the following options\n post.topics = post.topics.map(function(topic){\n return utils.fromAscii(topic);\n });\n\n return post; \n};\n\n/**\n * Formats the output of a received post message\n *\n * @method outputPostFormatter\n * @param {Object}\n * @returns {Object}\n */\nvar outputPostFormatter = function(post){\n\n post.expiry = utils.toDecimal(post.expiry);\n post.sent = utils.toDecimal(post.sent);\n post.ttl = utils.toDecimal(post.ttl);\n post.workProved = utils.toDecimal(post.workProved);\n post.payloadRaw = post.payload;\n post.payload = utils.toAscii(post.payload);\n\n if (utils.isJson(post.payload)) {\n post.payload = JSON.parse(post.payload);\n }\n\n // format the following options\n if (!post.topics) {\n post.topics = [];\n }\n post.topics = post.topics.map(function(topic){\n return utils.toAscii(topic);\n });\n\n return post;\n};\n\nmodule.exports = {\n inputDefaultBlockNumberFormatter: inputDefaultBlockNumberFormatter,\n inputBlockNumberFormatter: inputBlockNumberFormatter,\n inputTransactionFormatter: inputTransactionFormatter,\n inputPostFormatter: inputPostFormatter,\n outputBigNumberFormatter: outputBigNumberFormatter,\n outputTransactionFormatter: outputTransactionFormatter,\n outputBlockFormatter: outputBlockFormatter,\n outputLogFormatter: outputLogFormatter,\n outputPostFormatter: outputPostFormatter\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file function.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar web3 = require('../web3');\nvar coder = require('../solidity/coder');\nvar utils = require('../utils/utils');\n\n/**\n * This prototype should be used to call/sendTransaction to solidity functions\n */\nvar SolidityFunction = function (json, address) {\n this._inputTypes = json.inputs.map(function (i) {\n return i.type;\n });\n this._outputTypes = json.outputs.map(function (i) {\n return i.type;\n });\n this._constant = json.constant;\n this._name = utils.transformToFullName(json);\n this._address = address;\n};\n\nSolidityFunction.prototype.extractCallback = function (args) {\n if (utils.isFunction(args[args.length - 1])) {\n return args.pop(); // modify the args array!\n }\n};\n\n/**\n * Should be used to create payload from arguments\n *\n * @method toPayload\n * @param {Array} solidity function params\n * @param {Object} optional payload options\n */\nSolidityFunction.prototype.toPayload = function (args) {\n var options = {};\n if (args.length > this._inputTypes.length && utils.isObject(args[args.length -1])) {\n options = args[args.length - 1];\n }\n options.to = this._address;\n options.data = '0x' + this.signature() + coder.encodeParams(this._inputTypes, args);\n return options;\n};\n\n/**\n * Should be used to get function signature\n *\n * @method signature\n * @return {String} function signature\n */\nSolidityFunction.prototype.signature = function () {\n return web3.sha3(web3.fromAscii(this._name)).slice(2, 10);\n};\n\n\nSolidityFunction.prototype.unpackOutput = function (output) {\n if (output === null) {\n return;\n }\n\n output = output.length >= 2 ? output.slice(2) : output;\n var result = coder.decodeParams(this._outputTypes, output);\n return result.length === 1 ? result[0] : result;\n};\n\n/**\n * Calls a contract function.\n *\n * @method call\n * @param {...Object} Contract function arguments\n * @param {function} If the last argument is a function, the contract function\n * call will be asynchronous, and the callback will be passed the\n * error and result.\n * @return {String} output bytes\n */\nSolidityFunction.prototype.call = function () {\n var args = Array.prototype.slice.call(arguments);\n var callback = this.extractCallback(args);\n var payload = this.toPayload(args);\n\n if (!callback) {\n var output = web3.eth.call(payload);\n return this.unpackOutput(output);\n } \n \n var self = this;\n web3.eth.call(payload, function (error, output) {\n callback(error, self.unpackOutput(output));\n });\n};\n\n/**\n * Should be used to sendTransaction to solidity function\n *\n * @method sendTransaction\n * @param {Object} options\n */\nSolidityFunction.prototype.sendTransaction = function () {\n var args = Array.prototype.slice.call(arguments);\n var callback = this.extractCallback(args);\n var payload = this.toPayload(args);\n\n if (!callback) {\n web3.eth.sendTransaction(payload);\n return;\n }\n\n web3.eth.sendTransaction(payload, callback);\n};\n\n/**\n * Should be used to get function display name\n *\n * @method displayName\n * @return {String} display name of the function\n */\nSolidityFunction.prototype.displayName = function () {\n return utils.extractDisplayName(this._name);\n};\n\n/**\n * Should be used to get function type name\n *\n * @method typeName\n * @return {String} type name of the function\n */\nSolidityFunction.prototype.typeName = function () {\n return utils.extractTypeName(this._name);\n};\n\n/**\n * Should be called to get rpc requests from solidity function\n *\n * @method request\n * @returns {Object}\n */\nSolidityFunction.prototype.request = function () {\n var args = Array.prototype.slice.call(arguments);\n var callback = this.extractCallback(args);\n var payload = this.toPayload(args);\n var format = this.unpackOutput.bind(this);\n \n return {\n callback: callback,\n payload: payload, \n format: format\n };\n};\n\n/**\n * Should be called to execute function\n *\n * @method execute\n */\nSolidityFunction.prototype.execute = function () {\n var transaction = !this._constant;\n\n // send transaction\n if (transaction) {\n return this.sendTransaction.apply(this, Array.prototype.slice.call(arguments));\n }\n\n // call\n return this.call.apply(this, Array.prototype.slice.call(arguments));\n};\n\n/**\n * Should be called to attach function to contract\n *\n * @method attachToContract\n * @param {Contract}\n */\nSolidityFunction.prototype.attachToContract = function (contract) {\n var execute = this.execute.bind(this);\n execute.request = this.request.bind(this);\n execute.call = this.call.bind(this);\n execute.sendTransaction = this.sendTransaction.bind(this);\n var displayName = this.displayName();\n if (!contract[displayName]) {\n contract[displayName] = execute;\n }\n contract[displayName][this.typeName()] = execute; // circular!!!!\n};\n\nmodule.exports = SolidityFunction;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file httpprovider.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * Fabian Vogelsteller \n * @date 2014\n */\n\n\"use strict\";\n\nvar XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line\nvar errors = require('./errors');\n\nvar HttpProvider = function (host) {\n this.host = host || 'http://localhost:8545';\n};\n\nHttpProvider.prototype.send = function (payload) {\n var request = new XMLHttpRequest();\n\n request.open('POST', this.host, false);\n \n try {\n request.send(JSON.stringify(payload));\n } catch(error) {\n throw errors.InvalidConnection(this.host);\n }\n\n\n // check request.status\n // TODO: throw an error here! it cannot silently fail!!!\n //if (request.status !== 200) {\n //return;\n //}\n\n var result = request.responseText;\n\n try {\n result = JSON.parse(result);\n } catch(e) {\n throw errors.InvalidResponse(result); \n }\n\n return result;\n};\n\nHttpProvider.prototype.sendAsync = function (payload, callback) {\n var request = new XMLHttpRequest();\n request.onreadystatechange = function() {\n if (request.readyState === 4) {\n var result = request.responseText;\n var error = null;\n\n try {\n result = JSON.parse(result);\n } catch(e) {\n error = errors.InvalidResponse(result); \n }\n\n callback(error, result);\n }\n };\n\n request.open('POST', this.host, true);\n\n try {\n request.send(JSON.stringify(payload));\n } catch(error) {\n callback(errors.InvalidConnection(this.host));\n }\n};\n\nmodule.exports = HttpProvider;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file jsonrpc.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar Jsonrpc = function () {\n // singleton pattern\n if (arguments.callee._singletonInstance) {\n return arguments.callee._singletonInstance;\n }\n arguments.callee._singletonInstance = this;\n\n this.messageId = 1;\n};\n\n/**\n * @return {Jsonrpc} singleton\n */\nJsonrpc.getInstance = function () {\n var instance = new Jsonrpc();\n return instance;\n};\n\n/**\n * Should be called to valid json create payload object\n *\n * @method toPayload\n * @param {Function} method of jsonrpc call, required\n * @param {Array} params, an array of method params, optional\n * @returns {Object} valid jsonrpc payload object\n */\nJsonrpc.prototype.toPayload = function (method, params) {\n if (!method)\n console.error('jsonrpc method should be specified!');\n\n return {\n jsonrpc: '2.0',\n method: method,\n params: params || [],\n id: this.messageId++\n };\n};\n\n/**\n * Should be called to check if jsonrpc response is valid\n *\n * @method isValidResponse\n * @param {Object}\n * @returns {Boolean} true if response is valid, otherwise false\n */\nJsonrpc.prototype.isValidResponse = function (response) {\n return !!response &&\n !response.error &&\n response.jsonrpc === '2.0' &&\n typeof response.id === 'number' &&\n response.result !== undefined; // only undefined is not valid json object\n};\n\n/**\n * Should be called to create batch payload object\n *\n * @method toBatchPayload\n * @param {Array} messages, an array of objects with method (required) and params (optional) fields\n * @returns {Array} batch payload\n */\nJsonrpc.prototype.toBatchPayload = function (messages) {\n var self = this;\n return messages.map(function (message) {\n return self.toPayload(message.method, message.params);\n });\n};\n\nmodule.exports = Jsonrpc;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file method.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar RequestManager = require('./requestmanager');\nvar utils = require('../utils/utils');\nvar errors = require('./errors');\n\nvar Method = function (options) {\n this.name = options.name;\n this.call = options.call;\n this.params = options.params || 0;\n this.inputFormatter = options.inputFormatter;\n this.outputFormatter = options.outputFormatter;\n};\n\n/**\n * Should be used to determine name of the jsonrpc method based on arguments\n *\n * @method getCall\n * @param {Array} arguments\n * @return {String} name of jsonrpc method\n */\nMethod.prototype.getCall = function (args) {\n return utils.isFunction(this.call) ? this.call(args) : this.call;\n};\n\n/**\n * Should be used to extract callback from array of arguments. Modifies input param\n *\n * @method extractCallback\n * @param {Array} arguments\n * @return {Function|Null} callback, if exists\n */\nMethod.prototype.extractCallback = function (args) {\n if (utils.isFunction(args[args.length - 1])) {\n return args.pop(); // modify the args array!\n }\n};\n\n/**\n * Should be called to check if the number of arguments is correct\n * \n * @method validateArgs\n * @param {Array} arguments\n * @throws {Error} if it is not\n */\nMethod.prototype.validateArgs = function (args) {\n if (args.length !== this.params) {\n throw errors.InvalidNumberOfParams();\n }\n};\n\n/**\n * Should be called to format input args of method\n * \n * @method formatInput\n * @param {Array}\n * @return {Array}\n */\nMethod.prototype.formatInput = function (args) {\n if (!this.inputFormatter) {\n return args;\n }\n\n return this.inputFormatter.map(function (formatter, index) {\n return formatter ? formatter(args[index]) : args[index];\n });\n};\n\n/**\n * Should be called to format output(result) of method\n *\n * @method formatOutput\n * @param {Object}\n * @return {Object}\n */\nMethod.prototype.formatOutput = function (result) {\n return this.outputFormatter && result !== null ? this.outputFormatter(result) : result;\n};\n\n/**\n * Should attach function to method\n * \n * @method attachToObject\n * @param {Object}\n * @param {Function}\n */\nMethod.prototype.attachToObject = function (obj) {\n var func = this.send.bind(this);\n func.request = this.request.bind(this);\n func.call = this.call; // that's ugly. filter.js uses it\n var name = this.name.split('.');\n if (name.length > 1) {\n obj[name[0]] = obj[name[0]] || {};\n obj[name[0]][name[1]] = func;\n } else {\n obj[name[0]] = func; \n }\n};\n\n/**\n * Should create payload from given input args\n *\n * @method toPayload\n * @param {Array} args\n * @return {Object}\n */\nMethod.prototype.toPayload = function (args) {\n var call = this.getCall(args);\n var callback = this.extractCallback(args);\n var params = this.formatInput(args);\n this.validateArgs(params);\n\n return {\n method: call,\n params: params,\n callback: callback\n };\n};\n\n/**\n * Should be called to create pure JSONRPC request which can be used in batch request\n *\n * @method request\n * @param {...} params\n * @return {Object} jsonrpc request\n */\nMethod.prototype.request = function () {\n var payload = this.toPayload(Array.prototype.slice.call(arguments));\n payload.format = this.formatOutput.bind(this);\n return payload;\n};\n\n/**\n * Should send request to the API\n *\n * @method send\n * @param list of params\n * @return result\n */\nMethod.prototype.send = function () {\n var payload = this.toPayload(Array.prototype.slice.call(arguments));\n if (payload.callback) {\n var self = this;\n return RequestManager.getInstance().sendAsync(payload, function (err, result) {\n payload.callback(err, self.formatOutput(result));\n });\n }\n return this.formatOutput(RequestManager.getInstance().send(payload));\n};\n\nmodule.exports = Method;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file eth.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar utils = require('../utils/utils');\nvar Property = require('./property');\n\n/// @returns an array of objects describing web3.eth api methods\nvar methods = [\n];\n\n/// @returns an array of objects describing web3.eth api properties\nvar properties = [\n new Property({\n name: 'listening',\n getter: 'net_listening'\n }),\n new Property({\n name: 'peerCount',\n getter: 'net_peerCount',\n outputFormatter: utils.toDecimal\n })\n];\n\n\nmodule.exports = {\n methods: methods,\n properties: properties\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/**\n * @file property.js\n * @author Fabian Vogelsteller \n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar RequestManager = require('./requestmanager');\n\nvar Property = function (options) {\n this.name = options.name;\n this.getter = options.getter;\n this.setter = options.setter;\n this.outputFormatter = options.outputFormatter;\n this.inputFormatter = options.inputFormatter;\n};\n\n/**\n * Should be called to format input args of method\n * \n * @method formatInput\n * @param {Array}\n * @return {Array}\n */\nProperty.prototype.formatInput = function (arg) {\n return this.inputFormatter ? this.inputFormatter(arg) : arg;\n};\n\n/**\n * Should be called to format output(result) of method\n *\n * @method formatOutput\n * @param {Object}\n * @return {Object}\n */\nProperty.prototype.formatOutput = function (result) {\n return this.outputFormatter && result !== null ? this.outputFormatter(result) : result;\n};\n\n/**\n * Should attach function to method\n * \n * @method attachToObject\n * @param {Object}\n * @param {Function}\n */\nProperty.prototype.attachToObject = function (obj) {\n var proto = {\n get: this.get.bind(this),\n };\n\n var names = this.name.split('.');\n var name = names[0];\n if (names.length > 1) {\n obj[names[0]] = obj[names[0]] || {};\n obj = obj[names[0]];\n name = names[1];\n }\n \n Object.defineProperty(obj, name, proto);\n\n var toAsyncName = function (prefix, name) {\n return prefix + name.charAt(0).toUpperCase() + name.slice(1);\n };\n\n obj[toAsyncName('get', name)] = this.getAsync.bind(this);\n};\n\n/**\n * Should be used to get value of the property\n *\n * @method get\n * @return {Object} value of the property\n */\nProperty.prototype.get = function () {\n return this.formatOutput(RequestManager.getInstance().send({\n method: this.getter\n }));\n};\n\n/**\n * Should be used to asynchrounously get value of property\n *\n * @method getAsync\n * @param {Function}\n */\nProperty.prototype.getAsync = function (callback) {\n var self = this;\n RequestManager.getInstance().sendAsync({\n method: this.getter\n }, function (err, result) {\n if (err) {\n return callback(err);\n }\n callback(err, self.formatOutput(result));\n });\n};\n\nmodule.exports = Property;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file qtsync.js\n * @authors:\n * Marek Kotewicz \n * Marian Oancea \n * @date 2014\n */\n\nvar QtSyncProvider = function () {\n};\n\nQtSyncProvider.prototype.send = function (payload) {\n var result = navigator.qt.callMethod(JSON.stringify(payload));\n return JSON.parse(result);\n};\n\nmodule.exports = QtSyncProvider;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** \n * @file requestmanager.js\n * @author Jeffrey Wilcke \n * @author Marek Kotewicz \n * @author Marian Oancea \n * @author Fabian Vogelsteller \n * @author Gav Wood \n * @date 2014\n */\n\nvar Jsonrpc = require('./jsonrpc');\nvar utils = require('../utils/utils');\nvar c = require('../utils/config');\nvar errors = require('./errors');\n\n/**\n * It's responsible for passing messages to providers\n * It's also responsible for polling the ethereum node for incoming messages\n * Default poll timeout is 1 second\n * Singleton\n */\nvar RequestManager = function (provider) {\n // singleton pattern\n if (arguments.callee._singletonInstance) {\n return arguments.callee._singletonInstance;\n }\n arguments.callee._singletonInstance = this;\n\n this.provider = provider;\n this.polls = [];\n this.timeout = null;\n this.poll();\n};\n\n/**\n * @return {RequestManager} singleton\n */\nRequestManager.getInstance = function () {\n var instance = new RequestManager();\n return instance;\n};\n\n/**\n * Should be used to synchronously send request\n *\n * @method send\n * @param {Object} data\n * @return {Object}\n */\nRequestManager.prototype.send = function (data) {\n if (!this.provider) {\n console.error(errors.InvalidProvider());\n return null;\n }\n\n var payload = Jsonrpc.getInstance().toPayload(data.method, data.params);\n var result = this.provider.send(payload);\n\n if (!Jsonrpc.getInstance().isValidResponse(result)) {\n throw errors.InvalidResponse(result);\n }\n\n return result.result;\n};\n\n/**\n * Should be used to asynchronously send request\n *\n * @method sendAsync\n * @param {Object} data\n * @param {Function} callback\n */\nRequestManager.prototype.sendAsync = function (data, callback) {\n if (!this.provider) {\n return callback(errors.InvalidProvider());\n }\n\n var payload = Jsonrpc.getInstance().toPayload(data.method, data.params);\n this.provider.sendAsync(payload, function (err, result) {\n if (err) {\n return callback(err);\n }\n \n if (!Jsonrpc.getInstance().isValidResponse(result)) {\n return callback(errors.InvalidResponse(result));\n }\n\n callback(null, result.result);\n });\n};\n\n/**\n * Should be called to asynchronously send batch request\n *\n * @method sendBatch\n * @param {Array} batch data\n * @param {Function} callback\n */\nRequestManager.prototype.sendBatch = function (data, callback) {\n if (!this.provider) {\n return callback(errors.InvalidProvider());\n }\n\n var payload = Jsonrpc.getInstance().toBatchPayload(data);\n\n this.provider.sendAsync(payload, function (err, results) {\n if (err) {\n return callback(err);\n }\n\n if (!utils.isArray(results)) {\n return callback(errors.InvalidResponse(results));\n }\n\n callback(err, results);\n }); \n};\n\n/**\n * Should be used to set provider of request manager\n *\n * @method setProvider\n * @param {Object}\n */\nRequestManager.prototype.setProvider = function (p) {\n this.provider = p;\n};\n\n/*jshint maxparams:4 */\n\n/**\n * Should be used to start polling\n *\n * @method startPolling\n * @param {Object} data\n * @param {Number} pollId\n * @param {Function} callback\n * @param {Function} uninstall\n *\n * @todo cleanup number of params\n */\nRequestManager.prototype.startPolling = function (data, pollId, callback, uninstall) {\n this.polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall});\n};\n/*jshint maxparams:3 */\n\n/**\n * Should be used to stop polling for filter with given id\n *\n * @method stopPolling\n * @param {Number} pollId\n */\nRequestManager.prototype.stopPolling = function (pollId) {\n for (var i = this.polls.length; i--;) {\n var poll = this.polls[i];\n if (poll.id === pollId) {\n this.polls.splice(i, 1);\n }\n }\n};\n\n/**\n * Should be called to reset polling mechanism of request manager\n *\n * @method reset\n */\nRequestManager.prototype.reset = function () {\n this.polls.forEach(function (poll) {\n poll.uninstall(poll.id); \n });\n this.polls = [];\n\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = null;\n }\n this.poll();\n};\n\n/**\n * Should be called to poll for changes on filter with given id\n *\n * @method poll\n */\nRequestManager.prototype.poll = function () {\n this.timeout = setTimeout(this.poll.bind(this), c.ETH_POLLING_TIMEOUT);\n\n if (!this.polls.length) {\n return;\n }\n\n if (!this.provider) {\n console.error(errors.InvalidProvider());\n return;\n }\n\n var payload = Jsonrpc.getInstance().toBatchPayload(this.polls.map(function (data) {\n return data.data;\n }));\n\n var self = this;\n this.provider.sendAsync(payload, function (error, results) {\n // TODO: console log?\n if (error) {\n return;\n }\n \n if (!utils.isArray(results)) {\n throw errors.InvalidResponse(results);\n }\n\n results.map(function (result, index) {\n result.callback = self.polls[index].callback;\n return result;\n }).filter(function (result) {\n var valid = Jsonrpc.getInstance().isValidResponse(result);\n if (!valid) {\n result.callback(errors.InvalidResponse(result));\n }\n return valid;\n }).filter(function (result) {\n return utils.isArray(result.result) && result.result.length > 0;\n }).forEach(function (result) {\n result.callback(null, result.result);\n });\n });\n};\n\nmodule.exports = RequestManager;\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file shh.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar Method = require('./method');\nvar formatters = require('./formatters');\n\nvar post = new Method({\n name: 'post', \n call: 'shh_post', \n params: 1,\n inputFormatter: [formatters.inputPostFormatter]\n});\n\nvar newIdentity = new Method({\n name: 'newIdentity',\n call: 'shh_newIdentity',\n params: 0\n});\n\nvar hasIdentity = new Method({\n name: 'hasIdentity',\n call: 'shh_hasIdentity',\n params: 1\n});\n\nvar newGroup = new Method({\n name: 'newGroup',\n call: 'shh_newGroup',\n params: 0\n});\n\nvar addToGroup = new Method({\n name: 'addToGroup',\n call: 'shh_addToGroup',\n params: 0\n});\n\nvar methods = [\n post,\n newIdentity,\n hasIdentity,\n newGroup,\n addToGroup\n];\n\nmodule.exports = {\n methods: methods\n};\n\n", - "/*\n This file is part of ethereum.js.\n\n ethereum.js is free software: you can redistribute it and/or modify\n it under the terms of the GNU Lesser General Public License as published by\n the Free Software Foundation, either version 3 of the License, or\n (at your option) any later version.\n\n ethereum.js is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n GNU Lesser General Public License for more details.\n\n You should have received a copy of the GNU Lesser General Public License\n along with ethereum.js. If not, see .\n*/\n/** @file watches.js\n * @authors:\n * Marek Kotewicz \n * @date 2015\n */\n\nvar Method = require('./method');\n\n/// @returns an array of objects describing web3.eth.filter api methods\nvar eth = function () {\n var newFilterCall = function (args) {\n var type = args[0];\n\n switch(type) {\n case 'latest':\n args.pop();\n this.params = 0;\n return 'eth_newBlockFilter';\n case 'pending':\n args.pop();\n this.params = 0;\n return 'eth_newPendingTransactionFilter';\n default:\n return 'eth_newFilter';\n }\n };\n\n var newFilter = new Method({\n name: 'newFilter',\n call: newFilterCall,\n params: 1\n });\n\n var uninstallFilter = new Method({\n name: 'uninstallFilter',\n call: 'eth_uninstallFilter',\n params: 1\n });\n\n var getLogs = new Method({\n name: 'getLogs',\n call: 'eth_getFilterLogs',\n params: 1\n });\n\n var poll = new Method({\n name: 'poll',\n call: 'eth_getFilterChanges',\n params: 1\n });\n\n return [\n newFilter,\n uninstallFilter,\n getLogs,\n poll\n ];\n};\n\n/// @returns an array of objects describing web3.shh.watch api methods\nvar shh = function () {\n var newFilter = new Method({\n name: 'newFilter',\n call: 'shh_newFilter',\n params: 1\n });\n\n var uninstallFilter = new Method({\n name: 'uninstallFilter',\n call: 'shh_uninstallFilter',\n params: 1\n });\n\n var getLogs = new Method({\n name: 'getLogs',\n call: 'shh_getMessages',\n params: 1\n });\n\n var poll = new Method({\n name: 'poll',\n call: 'shh_getFilterChanges',\n params: 1\n });\n\n return [\n newFilter,\n uninstallFilter,\n getLogs,\n poll\n ];\n};\n\nmodule.exports = {\n eth: eth,\n shh: shh\n};\n\n", - null, - "/*! bignumber.js v2.0.7 https://github.com/MikeMcl/bignumber.js/LICENCE */\n\n;(function (global) {\n 'use strict';\n\n /*\n bignumber.js v2.0.7\n A JavaScript library for arbitrary-precision arithmetic.\n https://github.com/MikeMcl/bignumber.js\n Copyright (c) 2015 Michael Mclaughlin \n MIT Expat Licence\n */\n\n\n var BigNumber, crypto, parseNumeric,\n isNumeric = /^-?(\\d+(\\.\\d*)?|\\.\\d+)(e[+-]?\\d+)?$/i,\n mathceil = Math.ceil,\n mathfloor = Math.floor,\n notBool = ' not a boolean or binary digit',\n roundingMode = 'rounding mode',\n tooManyDigits = 'number type has more than 15 significant digits',\n ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_',\n BASE = 1e14,\n LOG_BASE = 14,\n MAX_SAFE_INTEGER = 0x1fffffffffffff, // 2^53 - 1\n // MAX_INT32 = 0x7fffffff, // 2^31 - 1\n POWS_TEN = [1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13],\n SQRT_BASE = 1e7,\n\n /*\n * The limit on the value of DECIMAL_PLACES, TO_EXP_NEG, TO_EXP_POS, MIN_EXP, MAX_EXP, and\n * the arguments to toExponential, toFixed, toFormat, and toPrecision, beyond which an\n * exception is thrown (if ERRORS is true).\n */\n MAX = 1E9; // 0 to MAX_INT32\n\n\n /*\n * Create and return a BigNumber constructor.\n */\n function another(configObj) {\n var div,\n\n // id tracks the caller function, so its name can be included in error messages.\n id = 0,\n P = BigNumber.prototype,\n ONE = new BigNumber(1),\n\n\n /********************************* EDITABLE DEFAULTS **********************************/\n\n\n /*\n * The default values below must be integers within the inclusive ranges stated.\n * The values can also be changed at run-time using BigNumber.config.\n */\n\n // The maximum number of decimal places for operations involving division.\n DECIMAL_PLACES = 20, // 0 to MAX\n\n /*\n * The rounding mode used when rounding to the above decimal places, and when using\n * toExponential, toFixed, toFormat and toPrecision, and round (default value).\n * UP 0 Away from zero.\n * DOWN 1 Towards zero.\n * CEIL 2 Towards +Infinity.\n * FLOOR 3 Towards -Infinity.\n * HALF_UP 4 Towards nearest neighbour. If equidistant, up.\n * HALF_DOWN 5 Towards nearest neighbour. If equidistant, down.\n * HALF_EVEN 6 Towards nearest neighbour. If equidistant, towards even neighbour.\n * HALF_CEIL 7 Towards nearest neighbour. If equidistant, towards +Infinity.\n * HALF_FLOOR 8 Towards nearest neighbour. If equidistant, towards -Infinity.\n */\n ROUNDING_MODE = 4, // 0 to 8\n\n // EXPONENTIAL_AT : [TO_EXP_NEG , TO_EXP_POS]\n\n // The exponent value at and beneath which toString returns exponential notation.\n // Number type: -7\n TO_EXP_NEG = -7, // 0 to -MAX\n\n // The exponent value at and above which toString returns exponential notation.\n // Number type: 21\n TO_EXP_POS = 21, // 0 to MAX\n\n // RANGE : [MIN_EXP, MAX_EXP]\n\n // The minimum exponent value, beneath which underflow to zero occurs.\n // Number type: -324 (5e-324)\n MIN_EXP = -1e7, // -1 to -MAX\n\n // The maximum exponent value, above which overflow to Infinity occurs.\n // Number type: 308 (1.7976931348623157e+308)\n // For MAX_EXP > 1e7, e.g. new BigNumber('1e100000000').plus(1) may be slow.\n MAX_EXP = 1e7, // 1 to MAX\n\n // Whether BigNumber Errors are ever thrown.\n ERRORS = true, // true or false\n\n // Change to intValidatorNoErrors if ERRORS is false.\n isValidInt = intValidatorWithErrors, // intValidatorWithErrors/intValidatorNoErrors\n\n // Whether to use cryptographically-secure random number generation, if available.\n CRYPTO = false, // true or false\n\n /*\n * The modulo mode used when calculating the modulus: a mod n.\n * The quotient (q = a / n) is calculated according to the corresponding rounding mode.\n * The remainder (r) is calculated as: r = a - n * q.\n *\n * UP 0 The remainder is positive if the dividend is negative, else is negative.\n * DOWN 1 The remainder has the same sign as the dividend.\n * This modulo mode is commonly known as 'truncated division' and is\n * equivalent to (a % n) in JavaScript.\n * FLOOR 3 The remainder has the same sign as the divisor (Python %).\n * HALF_EVEN 6 This modulo mode implements the IEEE 754 remainder function.\n * EUCLID 9 Euclidian division. q = sign(n) * floor(a / abs(n)).\n * The remainder is always positive.\n *\n * The truncated division, floored division, Euclidian division and IEEE 754 remainder\n * modes are commonly used for the modulus operation.\n * Although the other rounding modes can also be used, they may not give useful results.\n */\n MODULO_MODE = 1, // 0 to 9\n\n // The maximum number of significant digits of the result of the toPower operation.\n // If POW_PRECISION is 0, there will be unlimited significant digits.\n POW_PRECISION = 100, // 0 to MAX\n\n // The format specification used by the BigNumber.prototype.toFormat method.\n FORMAT = {\n decimalSeparator: '.',\n groupSeparator: ',',\n groupSize: 3,\n secondaryGroupSize: 0,\n fractionGroupSeparator: '\\xA0', // non-breaking space\n fractionGroupSize: 0\n };\n\n\n /******************************************************************************************/\n\n\n // CONSTRUCTOR\n\n\n /*\n * The BigNumber constructor and exported function.\n * Create and return a new instance of a BigNumber object.\n *\n * n {number|string|BigNumber} A numeric value.\n * [b] {number} The base of n. Integer, 2 to 64 inclusive.\n */\n function BigNumber( n, b ) {\n var c, e, i, num, len, str,\n x = this;\n\n // Enable constructor usage without new.\n if ( !( x instanceof BigNumber ) ) {\n\n // 'BigNumber() constructor call without new: {n}'\n if (ERRORS) raise( 26, 'constructor call without new', n );\n return new BigNumber( n, b );\n }\n\n // 'new BigNumber() base not an integer: {b}'\n // 'new BigNumber() base out of range: {b}'\n if ( b == null || !isValidInt( b, 2, 64, id, 'base' ) ) {\n\n // Duplicate.\n if ( n instanceof BigNumber ) {\n x.s = n.s;\n x.e = n.e;\n x.c = ( n = n.c ) ? n.slice() : n;\n id = 0;\n return;\n }\n\n if ( ( num = typeof n == 'number' ) && n * 0 == 0 ) {\n x.s = 1 / n < 0 ? ( n = -n, -1 ) : 1;\n\n // Fast path for integers.\n if ( n === ~~n ) {\n for ( e = 0, i = n; i >= 10; i /= 10, e++ );\n x.e = e;\n x.c = [n];\n id = 0;\n return;\n }\n\n str = n + '';\n } else {\n if ( !isNumeric.test( str = n + '' ) ) return parseNumeric( x, str, num );\n x.s = str.charCodeAt(0) === 45 ? ( str = str.slice(1), -1 ) : 1;\n }\n } else {\n b = b | 0;\n str = n + '';\n\n // Ensure return value is rounded to DECIMAL_PLACES as with other bases.\n // Allow exponential notation to be used with base 10 argument.\n if ( b == 10 ) {\n x = new BigNumber( n instanceof BigNumber ? n : str );\n return round( x, DECIMAL_PLACES + x.e + 1, ROUNDING_MODE );\n }\n\n // Avoid potential interpretation of Infinity and NaN as base 44+ values.\n // Any number in exponential form will fail due to the [Ee][+-].\n if ( ( num = typeof n == 'number' ) && n * 0 != 0 ||\n !( new RegExp( '^-?' + ( c = '[' + ALPHABET.slice( 0, b ) + ']+' ) +\n '(?:\\\\.' + c + ')?$',b < 37 ? 'i' : '' ) ).test(str) ) {\n return parseNumeric( x, str, num, b );\n }\n\n if (num) {\n x.s = 1 / n < 0 ? ( str = str.slice(1), -1 ) : 1;\n\n if ( ERRORS && str.replace( /^0\\.0*|\\./, '' ).length > 15 ) {\n\n // 'new BigNumber() number type has more than 15 significant digits: {n}'\n raise( id, tooManyDigits, n );\n }\n\n // Prevent later check for length on converted number.\n num = false;\n } else {\n x.s = str.charCodeAt(0) === 45 ? ( str = str.slice(1), -1 ) : 1;\n }\n\n str = convertBase( str, 10, b, x.s );\n }\n\n // Decimal point?\n if ( ( e = str.indexOf('.') ) > -1 ) str = str.replace( '.', '' );\n\n // Exponential form?\n if ( ( i = str.search( /e/i ) ) > 0 ) {\n\n // Determine exponent.\n if ( e < 0 ) e = i;\n e += +str.slice( i + 1 );\n str = str.substring( 0, i );\n } else if ( e < 0 ) {\n\n // Integer.\n e = str.length;\n }\n\n // Determine leading zeros.\n for ( i = 0; str.charCodeAt(i) === 48; i++ );\n\n // Determine trailing zeros.\n for ( len = str.length; str.charCodeAt(--len) === 48; );\n str = str.slice( i, len + 1 );\n\n if (str) {\n len = str.length;\n\n // Disallow numbers with over 15 significant digits if number type.\n // 'new BigNumber() number type has more than 15 significant digits: {n}'\n if ( num && ERRORS && len > 15 ) raise( id, tooManyDigits, x.s * n );\n\n e = e - i - 1;\n\n // Overflow?\n if ( e > MAX_EXP ) {\n\n // Infinity.\n x.c = x.e = null;\n\n // Underflow?\n } else if ( e < MIN_EXP ) {\n\n // Zero.\n x.c = [ x.e = 0 ];\n } else {\n x.e = e;\n x.c = [];\n\n // Transform base\n\n // e is the base 10 exponent.\n // i is where to slice str to get the first element of the coefficient array.\n i = ( e + 1 ) % LOG_BASE;\n if ( e < 0 ) i += LOG_BASE;\n\n if ( i < len ) {\n if (i) x.c.push( +str.slice( 0, i ) );\n\n for ( len -= LOG_BASE; i < len; ) {\n x.c.push( +str.slice( i, i += LOG_BASE ) );\n }\n\n str = str.slice(i);\n i = LOG_BASE - str.length;\n } else {\n i -= len;\n }\n\n for ( ; i--; str += '0' );\n x.c.push( +str );\n }\n } else {\n\n // Zero.\n x.c = [ x.e = 0 ];\n }\n\n id = 0;\n }\n\n\n // CONSTRUCTOR PROPERTIES\n\n\n BigNumber.another = another;\n\n BigNumber.ROUND_UP = 0;\n BigNumber.ROUND_DOWN = 1;\n BigNumber.ROUND_CEIL = 2;\n BigNumber.ROUND_FLOOR = 3;\n BigNumber.ROUND_HALF_UP = 4;\n BigNumber.ROUND_HALF_DOWN = 5;\n BigNumber.ROUND_HALF_EVEN = 6;\n BigNumber.ROUND_HALF_CEIL = 7;\n BigNumber.ROUND_HALF_FLOOR = 8;\n BigNumber.EUCLID = 9;\n\n\n /*\n * Configure infrequently-changing library-wide settings.\n *\n * Accept an object or an argument list, with one or many of the following properties or\n * parameters respectively:\n *\n * DECIMAL_PLACES {number} Integer, 0 to MAX inclusive\n * ROUNDING_MODE {number} Integer, 0 to 8 inclusive\n * EXPONENTIAL_AT {number|number[]} Integer, -MAX to MAX inclusive or\n * [integer -MAX to 0 incl., 0 to MAX incl.]\n * RANGE {number|number[]} Non-zero integer, -MAX to MAX inclusive or\n * [integer -MAX to -1 incl., integer 1 to MAX incl.]\n * ERRORS {boolean|number} true, false, 1 or 0\n * CRYPTO {boolean|number} true, false, 1 or 0\n * MODULO_MODE {number} 0 to 9 inclusive\n * POW_PRECISION {number} 0 to MAX inclusive\n * FORMAT {object} See BigNumber.prototype.toFormat\n * decimalSeparator {string}\n * groupSeparator {string}\n * groupSize {number}\n * secondaryGroupSize {number}\n * fractionGroupSeparator {string}\n * fractionGroupSize {number}\n *\n * (The values assigned to the above FORMAT object properties are not checked for validity.)\n *\n * E.g.\n * BigNumber.config(20, 4) is equivalent to\n * BigNumber.config({ DECIMAL_PLACES : 20, ROUNDING_MODE : 4 })\n *\n * Ignore properties/parameters set to null or undefined.\n * Return an object with the properties current values.\n */\n BigNumber.config = function () {\n var v, p,\n i = 0,\n r = {},\n a = arguments,\n o = a[0],\n has = o && typeof o == 'object'\n ? function () { if ( o.hasOwnProperty(p) ) return ( v = o[p] ) != null; }\n : function () { if ( a.length > i ) return ( v = a[i++] ) != null; };\n\n // DECIMAL_PLACES {number} Integer, 0 to MAX inclusive.\n // 'config() DECIMAL_PLACES not an integer: {v}'\n // 'config() DECIMAL_PLACES out of range: {v}'\n if ( has( p = 'DECIMAL_PLACES' ) && isValidInt( v, 0, MAX, 2, p ) ) {\n DECIMAL_PLACES = v | 0;\n }\n r[p] = DECIMAL_PLACES;\n\n // ROUNDING_MODE {number} Integer, 0 to 8 inclusive.\n // 'config() ROUNDING_MODE not an integer: {v}'\n // 'config() ROUNDING_MODE out of range: {v}'\n if ( has( p = 'ROUNDING_MODE' ) && isValidInt( v, 0, 8, 2, p ) ) {\n ROUNDING_MODE = v | 0;\n }\n r[p] = ROUNDING_MODE;\n\n // EXPONENTIAL_AT {number|number[]}\n // Integer, -MAX to MAX inclusive or [integer -MAX to 0 inclusive, 0 to MAX inclusive].\n // 'config() EXPONENTIAL_AT not an integer: {v}'\n // 'config() EXPONENTIAL_AT out of range: {v}'\n if ( has( p = 'EXPONENTIAL_AT' ) ) {\n\n if ( isArray(v) ) {\n if ( isValidInt( v[0], -MAX, 0, 2, p ) && isValidInt( v[1], 0, MAX, 2, p ) ) {\n TO_EXP_NEG = v[0] | 0;\n TO_EXP_POS = v[1] | 0;\n }\n } else if ( isValidInt( v, -MAX, MAX, 2, p ) ) {\n TO_EXP_NEG = -( TO_EXP_POS = ( v < 0 ? -v : v ) | 0 );\n }\n }\n r[p] = [ TO_EXP_NEG, TO_EXP_POS ];\n\n // RANGE {number|number[]} Non-zero integer, -MAX to MAX inclusive or\n // [integer -MAX to -1 inclusive, integer 1 to MAX inclusive].\n // 'config() RANGE not an integer: {v}'\n // 'config() RANGE cannot be zero: {v}'\n // 'config() RANGE out of range: {v}'\n if ( has( p = 'RANGE' ) ) {\n\n if ( isArray(v) ) {\n if ( isValidInt( v[0], -MAX, -1, 2, p ) && isValidInt( v[1], 1, MAX, 2, p ) ) {\n MIN_EXP = v[0] | 0;\n MAX_EXP = v[1] | 0;\n }\n } else if ( isValidInt( v, -MAX, MAX, 2, p ) ) {\n if ( v | 0 ) MIN_EXP = -( MAX_EXP = ( v < 0 ? -v : v ) | 0 );\n else if (ERRORS) raise( 2, p + ' cannot be zero', v );\n }\n }\n r[p] = [ MIN_EXP, MAX_EXP ];\n\n // ERRORS {boolean|number} true, false, 1 or 0.\n // 'config() ERRORS not a boolean or binary digit: {v}'\n if ( has( p = 'ERRORS' ) ) {\n\n if ( v === !!v || v === 1 || v === 0 ) {\n id = 0;\n isValidInt = ( ERRORS = !!v ) ? intValidatorWithErrors : intValidatorNoErrors;\n } else if (ERRORS) {\n raise( 2, p + notBool, v );\n }\n }\n r[p] = ERRORS;\n\n // CRYPTO {boolean|number} true, false, 1 or 0.\n // 'config() CRYPTO not a boolean or binary digit: {v}'\n // 'config() crypto unavailable: {crypto}'\n if ( has( p = 'CRYPTO' ) ) {\n\n if ( v === !!v || v === 1 || v === 0 ) {\n CRYPTO = !!( v && crypto && typeof crypto == 'object' );\n if ( v && !CRYPTO && ERRORS ) raise( 2, 'crypto unavailable', crypto );\n } else if (ERRORS) {\n raise( 2, p + notBool, v );\n }\n }\n r[p] = CRYPTO;\n\n // MODULO_MODE {number} Integer, 0 to 9 inclusive.\n // 'config() MODULO_MODE not an integer: {v}'\n // 'config() MODULO_MODE out of range: {v}'\n if ( has( p = 'MODULO_MODE' ) && isValidInt( v, 0, 9, 2, p ) ) {\n MODULO_MODE = v | 0;\n }\n r[p] = MODULO_MODE;\n\n // POW_PRECISION {number} Integer, 0 to MAX inclusive.\n // 'config() POW_PRECISION not an integer: {v}'\n // 'config() POW_PRECISION out of range: {v}'\n if ( has( p = 'POW_PRECISION' ) && isValidInt( v, 0, MAX, 2, p ) ) {\n POW_PRECISION = v | 0;\n }\n r[p] = POW_PRECISION;\n\n // FORMAT {object}\n // 'config() FORMAT not an object: {v}'\n if ( has( p = 'FORMAT' ) ) {\n\n if ( typeof v == 'object' ) {\n FORMAT = v;\n } else if (ERRORS) {\n raise( 2, p + ' not an object', v );\n }\n }\n r[p] = FORMAT;\n\n return r;\n };\n\n\n /*\n * Return a new BigNumber whose value is the maximum of the arguments.\n *\n * arguments {number|string|BigNumber}\n */\n BigNumber.max = function () { return maxOrMin( arguments, P.lt ); };\n\n\n /*\n * Return a new BigNumber whose value is the minimum of the arguments.\n *\n * arguments {number|string|BigNumber}\n */\n BigNumber.min = function () { return maxOrMin( arguments, P.gt ); };\n\n\n /*\n * Return a new BigNumber with a random value equal to or greater than 0 and less than 1,\n * and with dp, or DECIMAL_PLACES if dp is omitted, decimal places (or less if trailing\n * zeros are produced).\n *\n * [dp] {number} Decimal places. Integer, 0 to MAX inclusive.\n *\n * 'random() decimal places not an integer: {dp}'\n * 'random() decimal places out of range: {dp}'\n * 'random() crypto unavailable: {crypto}'\n */\n BigNumber.random = (function () {\n var pow2_53 = 0x20000000000000;\n\n // Return a 53 bit integer n, where 0 <= n < 9007199254740992.\n // Check if Math.random() produces more than 32 bits of randomness.\n // If it does, assume at least 53 bits are produced, otherwise assume at least 30 bits.\n // 0x40000000 is 2^30, 0x800000 is 2^23, 0x1fffff is 2^21 - 1.\n var random53bitInt = (Math.random() * pow2_53) & 0x1fffff\n ? function () { return mathfloor( Math.random() * pow2_53 ); }\n : function () { return ((Math.random() * 0x40000000 | 0) * 0x800000) +\n (Math.random() * 0x800000 | 0); };\n\n return function (dp) {\n var a, b, e, k, v,\n i = 0,\n c = [],\n rand = new BigNumber(ONE);\n\n dp = dp == null || !isValidInt( dp, 0, MAX, 14 ) ? DECIMAL_PLACES : dp | 0;\n k = mathceil( dp / LOG_BASE );\n\n if (CRYPTO) {\n\n // Browsers supporting crypto.getRandomValues.\n if ( crypto && crypto.getRandomValues ) {\n\n a = crypto.getRandomValues( new Uint32Array( k *= 2 ) );\n\n for ( ; i < k; ) {\n\n // 53 bits:\n // ((Math.pow(2, 32) - 1) * Math.pow(2, 21)).toString(2)\n // 11111 11111111 11111111 11111111 11100000 00000000 00000000\n // ((Math.pow(2, 32) - 1) >>> 11).toString(2)\n // 11111 11111111 11111111\n // 0x20000 is 2^21.\n v = a[i] * 0x20000 + (a[i + 1] >>> 11);\n\n // Rejection sampling:\n // 0 <= v < 9007199254740992\n // Probability that v >= 9e15, is\n // 7199254740992 / 9007199254740992 ~= 0.0008, i.e. 1 in 1251\n if ( v >= 9e15 ) {\n b = crypto.getRandomValues( new Uint32Array(2) );\n a[i] = b[0];\n a[i + 1] = b[1];\n } else {\n\n // 0 <= v <= 8999999999999999\n // 0 <= (v % 1e14) <= 99999999999999\n c.push( v % 1e14 );\n i += 2;\n }\n }\n i = k / 2;\n\n // Node.js supporting crypto.randomBytes.\n } else if ( crypto && crypto.randomBytes ) {\n\n // buffer\n a = crypto.randomBytes( k *= 7 );\n\n for ( ; i < k; ) {\n\n // 0x1000000000000 is 2^48, 0x10000000000 is 2^40\n // 0x100000000 is 2^32, 0x1000000 is 2^24\n // 11111 11111111 11111111 11111111 11111111 11111111 11111111\n // 0 <= v < 9007199254740992\n v = ( ( a[i] & 31 ) * 0x1000000000000 ) + ( a[i + 1] * 0x10000000000 ) +\n ( a[i + 2] * 0x100000000 ) + ( a[i + 3] * 0x1000000 ) +\n ( a[i + 4] << 16 ) + ( a[i + 5] << 8 ) + a[i + 6];\n\n if ( v >= 9e15 ) {\n crypto.randomBytes(7).copy( a, i );\n } else {\n\n // 0 <= (v % 1e14) <= 99999999999999\n c.push( v % 1e14 );\n i += 7;\n }\n }\n i = k / 7;\n } else if (ERRORS) {\n raise( 14, 'crypto unavailable', crypto );\n }\n }\n\n // Use Math.random: CRYPTO is false or crypto is unavailable and ERRORS is false.\n if (!i) {\n\n for ( ; i < k; ) {\n v = random53bitInt();\n if ( v < 9e15 ) c[i++] = v % 1e14;\n }\n }\n\n k = c[--i];\n dp %= LOG_BASE;\n\n // Convert trailing digits to zeros according to dp.\n if ( k && dp ) {\n v = POWS_TEN[LOG_BASE - dp];\n c[i] = mathfloor( k / v ) * v;\n }\n\n // Remove trailing elements which are zero.\n for ( ; c[i] === 0; c.pop(), i-- );\n\n // Zero?\n if ( i < 0 ) {\n c = [ e = 0 ];\n } else {\n\n // Remove leading elements which are zero and adjust exponent accordingly.\n for ( e = -1 ; c[0] === 0; c.shift(), e -= LOG_BASE);\n\n // Count the digits of the first element of c to determine leading zeros, and...\n for ( i = 1, v = c[0]; v >= 10; v /= 10, i++);\n\n // adjust the exponent accordingly.\n if ( i < LOG_BASE ) e -= LOG_BASE - i;\n }\n\n rand.e = e;\n rand.c = c;\n return rand;\n };\n })();\n\n\n // PRIVATE FUNCTIONS\n\n\n // Convert a numeric string of baseIn to a numeric string of baseOut.\n function convertBase( str, baseOut, baseIn, sign ) {\n var d, e, k, r, x, xc, y,\n i = str.indexOf( '.' ),\n dp = DECIMAL_PLACES,\n rm = ROUNDING_MODE;\n\n if ( baseIn < 37 ) str = str.toLowerCase();\n\n // Non-integer.\n if ( i >= 0 ) {\n k = POW_PRECISION;\n\n // Unlimited precision.\n POW_PRECISION = 0;\n str = str.replace( '.', '' );\n y = new BigNumber(baseIn);\n x = y.pow( str.length - i );\n POW_PRECISION = k;\n\n // Convert str as if an integer, then restore the fraction part by dividing the\n // result by its base raised to a power.\n y.c = toBaseOut( toFixedPoint( coeffToString( x.c ), x.e ), 10, baseOut );\n y.e = y.c.length;\n }\n\n // Convert the number as integer.\n xc = toBaseOut( str, baseIn, baseOut );\n e = k = xc.length;\n\n // Remove trailing zeros.\n for ( ; xc[--k] == 0; xc.pop() );\n if ( !xc[0] ) return '0';\n\n if ( i < 0 ) {\n --e;\n } else {\n x.c = xc;\n x.e = e;\n\n // sign is needed for correct rounding.\n x.s = sign;\n x = div( x, y, dp, rm, baseOut );\n xc = x.c;\n r = x.r;\n e = x.e;\n }\n\n d = e + dp + 1;\n\n // The rounding digit, i.e. the digit to the right of the digit that may be rounded up.\n i = xc[d];\n k = baseOut / 2;\n r = r || d < 0 || xc[d + 1] != null;\n\n r = rm < 4 ? ( i != null || r ) && ( rm == 0 || rm == ( x.s < 0 ? 3 : 2 ) )\n : i > k || i == k &&( rm == 4 || r || rm == 6 && xc[d - 1] & 1 ||\n rm == ( x.s < 0 ? 8 : 7 ) );\n\n if ( d < 1 || !xc[0] ) {\n\n // 1^-dp or 0.\n str = r ? toFixedPoint( '1', -dp ) : '0';\n } else {\n xc.length = d;\n\n if (r) {\n\n // Rounding up may mean the previous digit has to be rounded up and so on.\n for ( --baseOut; ++xc[--d] > baseOut; ) {\n xc[d] = 0;\n\n if ( !d ) {\n ++e;\n xc.unshift(1);\n }\n }\n }\n\n // Determine trailing zeros.\n for ( k = xc.length; !xc[--k]; );\n\n // E.g. [4, 11, 15] becomes 4bf.\n for ( i = 0, str = ''; i <= k; str += ALPHABET.charAt( xc[i++] ) );\n str = toFixedPoint( str, e );\n }\n\n // The caller will add the sign.\n return str;\n }\n\n\n // Perform division in the specified base. Called by div and convertBase.\n div = (function () {\n\n // Assume non-zero x and k.\n function multiply( x, k, base ) {\n var m, temp, xlo, xhi,\n carry = 0,\n i = x.length,\n klo = k % SQRT_BASE,\n khi = k / SQRT_BASE | 0;\n\n for ( x = x.slice(); i--; ) {\n xlo = x[i] % SQRT_BASE;\n xhi = x[i] / SQRT_BASE | 0;\n m = khi * xlo + xhi * klo;\n temp = klo * xlo + ( ( m % SQRT_BASE ) * SQRT_BASE ) + carry;\n carry = ( temp / base | 0 ) + ( m / SQRT_BASE | 0 ) + khi * xhi;\n x[i] = temp % base;\n }\n\n if (carry) x.unshift(carry);\n\n return x;\n }\n\n function compare( a, b, aL, bL ) {\n var i, cmp;\n\n if ( aL != bL ) {\n cmp = aL > bL ? 1 : -1;\n } else {\n\n for ( i = cmp = 0; i < aL; i++ ) {\n\n if ( a[i] != b[i] ) {\n cmp = a[i] > b[i] ? 1 : -1;\n break;\n }\n }\n }\n return cmp;\n }\n\n function subtract( a, b, aL, base ) {\n var i = 0;\n\n // Subtract b from a.\n for ( ; aL--; ) {\n a[aL] -= i;\n i = a[aL] < b[aL] ? 1 : 0;\n a[aL] = i * base + a[aL] - b[aL];\n }\n\n // Remove leading zeros.\n for ( ; !a[0] && a.length > 1; a.shift() );\n }\n\n // x: dividend, y: divisor.\n return function ( x, y, dp, rm, base ) {\n var cmp, e, i, more, n, prod, prodL, q, qc, rem, remL, rem0, xi, xL, yc0,\n yL, yz,\n s = x.s == y.s ? 1 : -1,\n xc = x.c,\n yc = y.c;\n\n // Either NaN, Infinity or 0?\n if ( !xc || !xc[0] || !yc || !yc[0] ) {\n\n return new BigNumber(\n\n // Return NaN if either NaN, or both Infinity or 0.\n !x.s || !y.s || ( xc ? yc && xc[0] == yc[0] : !yc ) ? NaN :\n\n // Return ±0 if x is ±0 or y is ±Infinity, or return ±Infinity as y is ±0.\n xc && xc[0] == 0 || !yc ? s * 0 : s / 0\n );\n }\n\n q = new BigNumber(s);\n qc = q.c = [];\n e = x.e - y.e;\n s = dp + e + 1;\n\n if ( !base ) {\n base = BASE;\n e = bitFloor( x.e / LOG_BASE ) - bitFloor( y.e / LOG_BASE );\n s = s / LOG_BASE | 0;\n }\n\n // Result exponent may be one less then the current value of e.\n // The coefficients of the BigNumbers from convertBase may have trailing zeros.\n for ( i = 0; yc[i] == ( xc[i] || 0 ); i++ );\n if ( yc[i] > ( xc[i] || 0 ) ) e--;\n\n if ( s < 0 ) {\n qc.push(1);\n more = true;\n } else {\n xL = xc.length;\n yL = yc.length;\n i = 0;\n s += 2;\n\n // Normalise xc and yc so highest order digit of yc is >= base / 2.\n\n n = mathfloor( base / ( yc[0] + 1 ) );\n\n // Not necessary, but to handle odd bases where yc[0] == ( base / 2 ) - 1.\n // if ( n > 1 || n++ == 1 && yc[0] < base / 2 ) {\n if ( n > 1 ) {\n yc = multiply( yc, n, base );\n xc = multiply( xc, n, base );\n yL = yc.length;\n xL = xc.length;\n }\n\n xi = yL;\n rem = xc.slice( 0, yL );\n remL = rem.length;\n\n // Add zeros to make remainder as long as divisor.\n for ( ; remL < yL; rem[remL++] = 0 );\n yz = yc.slice();\n yz.unshift(0);\n yc0 = yc[0];\n if ( yc[1] >= base / 2 ) yc0++;\n // Not necessary, but to prevent trial digit n > base, when using base 3.\n // else if ( base == 3 && yc0 == 1 ) yc0 = 1 + 1e-15;\n\n do {\n n = 0;\n\n // Compare divisor and remainder.\n cmp = compare( yc, rem, yL, remL );\n\n // If divisor < remainder.\n if ( cmp < 0 ) {\n\n // Calculate trial digit, n.\n\n rem0 = rem[0];\n if ( yL != remL ) rem0 = rem0 * base + ( rem[1] || 0 );\n\n // n is how many times the divisor goes into the current remainder.\n n = mathfloor( rem0 / yc0 );\n\n // Algorithm:\n // 1. product = divisor * trial digit (n)\n // 2. if product > remainder: product -= divisor, n--\n // 3. remainder -= product\n // 4. if product was < remainder at 2:\n // 5. compare new remainder and divisor\n // 6. If remainder > divisor: remainder -= divisor, n++\n\n if ( n > 1 ) {\n\n // n may be > base only when base is 3.\n if (n >= base) n = base - 1;\n\n // product = divisor * trial digit.\n prod = multiply( yc, n, base );\n prodL = prod.length;\n remL = rem.length;\n\n // Compare product and remainder.\n // If product > remainder.\n // Trial digit n too high.\n // n is 1 too high about 5% of the time, and is not known to have\n // ever been more than 1 too high.\n while ( compare( prod, rem, prodL, remL ) == 1 ) {\n n--;\n\n // Subtract divisor from product.\n subtract( prod, yL < prodL ? yz : yc, prodL, base );\n prodL = prod.length;\n cmp = 1;\n }\n } else {\n\n // n is 0 or 1, cmp is -1.\n // If n is 0, there is no need to compare yc and rem again below,\n // so change cmp to 1 to avoid it.\n // If n is 1, leave cmp as -1, so yc and rem are compared again.\n if ( n == 0 ) {\n\n // divisor < remainder, so n must be at least 1.\n cmp = n = 1;\n }\n\n // product = divisor\n prod = yc.slice();\n prodL = prod.length;\n }\n\n if ( prodL < remL ) prod.unshift(0);\n\n // Subtract product from remainder.\n subtract( rem, prod, remL, base );\n remL = rem.length;\n\n // If product was < remainder.\n if ( cmp == -1 ) {\n\n // Compare divisor and new remainder.\n // If divisor < new remainder, subtract divisor from remainder.\n // Trial digit n too low.\n // n is 1 too low about 5% of the time, and very rarely 2 too low.\n while ( compare( yc, rem, yL, remL ) < 1 ) {\n n++;\n\n // Subtract divisor from remainder.\n subtract( rem, yL < remL ? yz : yc, remL, base );\n remL = rem.length;\n }\n }\n } else if ( cmp === 0 ) {\n n++;\n rem = [0];\n } // else cmp === 1 and n will be 0\n\n // Add the next digit, n, to the result array.\n qc[i++] = n;\n\n // Update the remainder.\n if ( rem[0] ) {\n rem[remL++] = xc[xi] || 0;\n } else {\n rem = [ xc[xi] ];\n remL = 1;\n }\n } while ( ( xi++ < xL || rem[0] != null ) && s-- );\n\n more = rem[0] != null;\n\n // Leading zero?\n if ( !qc[0] ) qc.shift();\n }\n\n if ( base == BASE ) {\n\n // To calculate q.e, first get the number of digits of qc[0].\n for ( i = 1, s = qc[0]; s >= 10; s /= 10, i++ );\n round( q, dp + ( q.e = i + e * LOG_BASE - 1 ) + 1, rm, more );\n\n // Caller is convertBase.\n } else {\n q.e = e;\n q.r = +more;\n }\n\n return q;\n };\n })();\n\n\n /*\n * Return a string representing the value of BigNumber n in fixed-point or exponential\n * notation rounded to the specified decimal places or significant digits.\n *\n * n is a BigNumber.\n * i is the index of the last digit required (i.e. the digit that may be rounded up).\n * rm is the rounding mode.\n * caller is caller id: toExponential 19, toFixed 20, toFormat 21, toPrecision 24.\n */\n function format( n, i, rm, caller ) {\n var c0, e, ne, len, str;\n\n rm = rm != null && isValidInt( rm, 0, 8, caller, roundingMode )\n ? rm | 0 : ROUNDING_MODE;\n\n if ( !n.c ) return n.toString();\n c0 = n.c[0];\n ne = n.e;\n\n if ( i == null ) {\n str = coeffToString( n.c );\n str = caller == 19 || caller == 24 && ne <= TO_EXP_NEG\n ? toExponential( str, ne )\n : toFixedPoint( str, ne );\n } else {\n n = round( new BigNumber(n), i, rm );\n\n // n.e may have changed if the value was rounded up.\n e = n.e;\n\n str = coeffToString( n.c );\n len = str.length;\n\n // toPrecision returns exponential notation if the number of significant digits\n // specified is less than the number of digits necessary to represent the integer\n // part of the value in fixed-point notation.\n\n // Exponential notation.\n if ( caller == 19 || caller == 24 && ( i <= e || e <= TO_EXP_NEG ) ) {\n\n // Append zeros?\n for ( ; len < i; str += '0', len++ );\n str = toExponential( str, e );\n\n // Fixed-point notation.\n } else {\n i -= ne;\n str = toFixedPoint( str, e );\n\n // Append zeros?\n if ( e + 1 > len ) {\n if ( --i > 0 ) for ( str += '.'; i--; str += '0' );\n } else {\n i += e - len;\n if ( i > 0 ) {\n if ( e + 1 == len ) str += '.';\n for ( ; i--; str += '0' );\n }\n }\n }\n }\n\n return n.s < 0 && c0 ? '-' + str : str;\n }\n\n\n // Handle BigNumber.max and BigNumber.min.\n function maxOrMin( args, method ) {\n var m, n,\n i = 0;\n\n if ( isArray( args[0] ) ) args = args[0];\n m = new BigNumber( args[0] );\n\n for ( ; ++i < args.length; ) {\n n = new BigNumber( args[i] );\n\n // If any number is NaN, return NaN.\n if ( !n.s ) {\n m = n;\n break;\n } else if ( method.call( m, n ) ) {\n m = n;\n }\n }\n\n return m;\n }\n\n\n /*\n * Return true if n is an integer in range, otherwise throw.\n * Use for argument validation when ERRORS is true.\n */\n function intValidatorWithErrors( n, min, max, caller, name ) {\n if ( n < min || n > max || n != truncate(n) ) {\n raise( caller, ( name || 'decimal places' ) +\n ( n < min || n > max ? ' out of range' : ' not an integer' ), n );\n }\n\n return true;\n }\n\n\n /*\n * Strip trailing zeros, calculate base 10 exponent and check against MIN_EXP and MAX_EXP.\n * Called by minus, plus and times.\n */\n function normalise( n, c, e ) {\n var i = 1,\n j = c.length;\n\n // Remove trailing zeros.\n for ( ; !c[--j]; c.pop() );\n\n // Calculate the base 10 exponent. First get the number of digits of c[0].\n for ( j = c[0]; j >= 10; j /= 10, i++ );\n\n // Overflow?\n if ( ( e = i + e * LOG_BASE - 1 ) > MAX_EXP ) {\n\n // Infinity.\n n.c = n.e = null;\n\n // Underflow?\n } else if ( e < MIN_EXP ) {\n\n // Zero.\n n.c = [ n.e = 0 ];\n } else {\n n.e = e;\n n.c = c;\n }\n\n return n;\n }\n\n\n // Handle values that fail the validity test in BigNumber.\n parseNumeric = (function () {\n var basePrefix = /^(-?)0([xbo])/i,\n dotAfter = /^([^.]+)\\.$/,\n dotBefore = /^\\.([^.]+)$/,\n isInfinityOrNaN = /^-?(Infinity|NaN)$/,\n whitespaceOrPlus = /^\\s*\\+|^\\s+|\\s+$/g;\n\n return function ( x, str, num, b ) {\n var base,\n s = num ? str : str.replace( whitespaceOrPlus, '' );\n\n // No exception on ±Infinity or NaN.\n if ( isInfinityOrNaN.test(s) ) {\n x.s = isNaN(s) ? null : s < 0 ? -1 : 1;\n } else {\n if ( !num ) {\n\n // basePrefix = /^(-?)0([xbo])(?=\\w[\\w.]*$)/i\n s = s.replace( basePrefix, function ( m, p1, p2 ) {\n base = ( p2 = p2.toLowerCase() ) == 'x' ? 16 : p2 == 'b' ? 2 : 8;\n return !b || b == base ? p1 : m;\n });\n\n if (b) {\n base = b;\n\n // E.g. '1.' to '1', '.1' to '0.1'\n s = s.replace( dotAfter, '$1' ).replace( dotBefore, '0.$1' );\n }\n\n if ( str != s ) return new BigNumber( s, base );\n }\n\n // 'new BigNumber() not a number: {n}'\n // 'new BigNumber() not a base {b} number: {n}'\n if (ERRORS) raise( id, 'not a' + ( b ? ' base ' + b : '' ) + ' number', str );\n x.s = null;\n }\n\n x.c = x.e = null;\n id = 0;\n }\n })();\n\n\n // Throw a BigNumber Error.\n function raise( caller, msg, val ) {\n var error = new Error( [\n 'new BigNumber', // 0\n 'cmp', // 1\n 'config', // 2\n 'div', // 3\n 'divToInt', // 4\n 'eq', // 5\n 'gt', // 6\n 'gte', // 7\n 'lt', // 8\n 'lte', // 9\n 'minus', // 10\n 'mod', // 11\n 'plus', // 12\n 'precision', // 13\n 'random', // 14\n 'round', // 15\n 'shift', // 16\n 'times', // 17\n 'toDigits', // 18\n 'toExponential', // 19\n 'toFixed', // 20\n 'toFormat', // 21\n 'toFraction', // 22\n 'pow', // 23\n 'toPrecision', // 24\n 'toString', // 25\n 'BigNumber' // 26\n ][caller] + '() ' + msg + ': ' + val );\n\n error.name = 'BigNumber Error';\n id = 0;\n throw error;\n }\n\n\n /*\n * Round x to sd significant digits using rounding mode rm. Check for over/under-flow.\n * If r is truthy, it is known that there are more digits after the rounding digit.\n */\n function round( x, sd, rm, r ) {\n var d, i, j, k, n, ni, rd,\n xc = x.c,\n pows10 = POWS_TEN;\n\n // if x is not Infinity or NaN...\n if (xc) {\n\n // rd is the rounding digit, i.e. the digit after the digit that may be rounded up.\n // n is a base 1e14 number, the value of the element of array x.c containing rd.\n // ni is the index of n within x.c.\n // d is the number of digits of n.\n // i is the index of rd within n including leading zeros.\n // j is the actual index of rd within n (if < 0, rd is a leading zero).\n out: {\n\n // Get the number of digits of the first element of xc.\n for ( d = 1, k = xc[0]; k >= 10; k /= 10, d++ );\n i = sd - d;\n\n // If the rounding digit is in the first element of xc...\n if ( i < 0 ) {\n i += LOG_BASE;\n j = sd;\n n = xc[ ni = 0 ];\n\n // Get the rounding digit at index j of n.\n rd = n / pows10[ d - j - 1 ] % 10 | 0;\n } else {\n ni = mathceil( ( i + 1 ) / LOG_BASE );\n\n if ( ni >= xc.length ) {\n\n if (r) {\n\n // Needed by sqrt.\n for ( ; xc.length <= ni; xc.push(0) );\n n = rd = 0;\n d = 1;\n i %= LOG_BASE;\n j = i - LOG_BASE + 1;\n } else {\n break out;\n }\n } else {\n n = k = xc[ni];\n\n // Get the number of digits of n.\n for ( d = 1; k >= 10; k /= 10, d++ );\n\n // Get the index of rd within n.\n i %= LOG_BASE;\n\n // Get the index of rd within n, adjusted for leading zeros.\n // The number of leading zeros of n is given by LOG_BASE - d.\n j = i - LOG_BASE + d;\n\n // Get the rounding digit at index j of n.\n rd = j < 0 ? 0 : n / pows10[ d - j - 1 ] % 10 | 0;\n }\n }\n\n r = r || sd < 0 ||\n\n // Are there any non-zero digits after the rounding digit?\n // The expression n % pows10[ d - j - 1 ] returns all digits of n to the right\n // of the digit at j, e.g. if n is 908714 and j is 2, the expression gives 714.\n xc[ni + 1] != null || ( j < 0 ? n : n % pows10[ d - j - 1 ] );\n\n r = rm < 4\n ? ( rd || r ) && ( rm == 0 || rm == ( x.s < 0 ? 3 : 2 ) )\n : rd > 5 || rd == 5 && ( rm == 4 || r || rm == 6 &&\n\n // Check whether the digit to the left of the rounding digit is odd.\n ( ( i > 0 ? j > 0 ? n / pows10[ d - j ] : 0 : xc[ni - 1] ) % 10 ) & 1 ||\n rm == ( x.s < 0 ? 8 : 7 ) );\n\n if ( sd < 1 || !xc[0] ) {\n xc.length = 0;\n\n if (r) {\n\n // Convert sd to decimal places.\n sd -= x.e + 1;\n\n // 1, 0.1, 0.01, 0.001, 0.0001 etc.\n xc[0] = pows10[ sd % LOG_BASE ];\n x.e = -sd || 0;\n } else {\n\n // Zero.\n xc[0] = x.e = 0;\n }\n\n return x;\n }\n\n // Remove excess digits.\n if ( i == 0 ) {\n xc.length = ni;\n k = 1;\n ni--;\n } else {\n xc.length = ni + 1;\n k = pows10[ LOG_BASE - i ];\n\n // E.g. 56700 becomes 56000 if 7 is the rounding digit.\n // j > 0 means i > number of leading zeros of n.\n xc[ni] = j > 0 ? mathfloor( n / pows10[ d - j ] % pows10[j] ) * k : 0;\n }\n\n // Round up?\n if (r) {\n\n for ( ; ; ) {\n\n // If the digit to be rounded up is in the first element of xc...\n if ( ni == 0 ) {\n\n // i will be the length of xc[0] before k is added.\n for ( i = 1, j = xc[0]; j >= 10; j /= 10, i++ );\n j = xc[0] += k;\n for ( k = 1; j >= 10; j /= 10, k++ );\n\n // if i != k the length has increased.\n if ( i != k ) {\n x.e++;\n if ( xc[0] == BASE ) xc[0] = 1;\n }\n\n break;\n } else {\n xc[ni] += k;\n if ( xc[ni] != BASE ) break;\n xc[ni--] = 0;\n k = 1;\n }\n }\n }\n\n // Remove trailing zeros.\n for ( i = xc.length; xc[--i] === 0; xc.pop() );\n }\n\n // Overflow? Infinity.\n if ( x.e > MAX_EXP ) {\n x.c = x.e = null;\n\n // Underflow? Zero.\n } else if ( x.e < MIN_EXP ) {\n x.c = [ x.e = 0 ];\n }\n }\n\n return x;\n }\n\n\n // PROTOTYPE/INSTANCE METHODS\n\n\n /*\n * Return a new BigNumber whose value is the absolute value of this BigNumber.\n */\n P.absoluteValue = P.abs = function () {\n var x = new BigNumber(this);\n if ( x.s < 0 ) x.s = 1;\n return x;\n };\n\n\n /*\n * Return a new BigNumber whose value is the value of this BigNumber rounded to a whole\n * number in the direction of Infinity.\n */\n P.ceil = function () {\n return round( new BigNumber(this), this.e + 1, 2 );\n };\n\n\n /*\n * Return\n * 1 if the value of this BigNumber is greater than the value of BigNumber(y, b),\n * -1 if the value of this BigNumber is less than the value of BigNumber(y, b),\n * 0 if they have the same value,\n * or null if the value of either is NaN.\n */\n P.comparedTo = P.cmp = function ( y, b ) {\n id = 1;\n return compare( this, new BigNumber( y, b ) );\n };\n\n\n /*\n * Return the number of decimal places of the value of this BigNumber, or null if the value\n * of this BigNumber is ±Infinity or NaN.\n */\n P.decimalPlaces = P.dp = function () {\n var n, v,\n c = this.c;\n\n if ( !c ) return null;\n n = ( ( v = c.length - 1 ) - bitFloor( this.e / LOG_BASE ) ) * LOG_BASE;\n\n // Subtract the number of trailing zeros of the last number.\n if ( v = c[v] ) for ( ; v % 10 == 0; v /= 10, n-- );\n if ( n < 0 ) n = 0;\n\n return n;\n };\n\n\n /*\n * n / 0 = I\n * n / N = N\n * n / I = 0\n * 0 / n = 0\n * 0 / 0 = N\n * 0 / N = N\n * 0 / I = 0\n * N / n = N\n * N / 0 = N\n * N / N = N\n * N / I = N\n * I / n = I\n * I / 0 = I\n * I / N = N\n * I / I = N\n *\n * Return a new BigNumber whose value is the value of this BigNumber divided by the value of\n * BigNumber(y, b), rounded according to DECIMAL_PLACES and ROUNDING_MODE.\n */\n P.dividedBy = P.div = function ( y, b ) {\n id = 3;\n return div( this, new BigNumber( y, b ), DECIMAL_PLACES, ROUNDING_MODE );\n };\n\n\n /*\n * Return a new BigNumber whose value is the integer part of dividing the value of this\n * BigNumber by the value of BigNumber(y, b).\n */\n P.dividedToIntegerBy = P.divToInt = function ( y, b ) {\n id = 4;\n return div( this, new BigNumber( y, b ), 0, 1 );\n };\n\n\n /*\n * Return true if the value of this BigNumber is equal to the value of BigNumber(y, b),\n * otherwise returns false.\n */\n P.equals = P.eq = function ( y, b ) {\n id = 5;\n return compare( this, new BigNumber( y, b ) ) === 0;\n };\n\n\n /*\n * Return a new BigNumber whose value is the value of this BigNumber rounded to a whole\n * number in the direction of -Infinity.\n */\n P.floor = function () {\n return round( new BigNumber(this), this.e + 1, 3 );\n };\n\n\n /*\n * Return true if the value of this BigNumber is greater than the value of BigNumber(y, b),\n * otherwise returns false.\n */\n P.greaterThan = P.gt = function ( y, b ) {\n id = 6;\n return compare( this, new BigNumber( y, b ) ) > 0;\n };\n\n\n /*\n * Return true if the value of this BigNumber is greater than or equal to the value of\n * BigNumber(y, b), otherwise returns false.\n */\n P.greaterThanOrEqualTo = P.gte = function ( y, b ) {\n id = 7;\n return ( b = compare( this, new BigNumber( y, b ) ) ) === 1 || b === 0;\n\n };\n\n\n /*\n * Return true if the value of this BigNumber is a finite number, otherwise returns false.\n */\n P.isFinite = function () {\n return !!this.c;\n };\n\n\n /*\n * Return true if the value of this BigNumber is an integer, otherwise return false.\n */\n P.isInteger = P.isInt = function () {\n return !!this.c && bitFloor( this.e / LOG_BASE ) > this.c.length - 2;\n };\n\n\n /*\n * Return true if the value of this BigNumber is NaN, otherwise returns false.\n */\n P.isNaN = function () {\n return !this.s;\n };\n\n\n /*\n * Return true if the value of this BigNumber is negative, otherwise returns false.\n */\n P.isNegative = P.isNeg = function () {\n return this.s < 0;\n };\n\n\n /*\n * Return true if the value of this BigNumber is 0 or -0, otherwise returns false.\n */\n P.isZero = function () {\n return !!this.c && this.c[0] == 0;\n };\n\n\n /*\n * Return true if the value of this BigNumber is less than the value of BigNumber(y, b),\n * otherwise returns false.\n */\n P.lessThan = P.lt = function ( y, b ) {\n id = 8;\n return compare( this, new BigNumber( y, b ) ) < 0;\n };\n\n\n /*\n * Return true if the value of this BigNumber is less than or equal to the value of\n * BigNumber(y, b), otherwise returns false.\n */\n P.lessThanOrEqualTo = P.lte = function ( y, b ) {\n id = 9;\n return ( b = compare( this, new BigNumber( y, b ) ) ) === -1 || b === 0;\n };\n\n\n /*\n * n - 0 = n\n * n - N = N\n * n - I = -I\n * 0 - n = -n\n * 0 - 0 = 0\n * 0 - N = N\n * 0 - I = -I\n * N - n = N\n * N - 0 = N\n * N - N = N\n * N - I = N\n * I - n = I\n * I - 0 = I\n * I - N = N\n * I - I = N\n *\n * Return a new BigNumber whose value is the value of this BigNumber minus the value of\n * BigNumber(y, b).\n */\n P.minus = P.sub = function ( y, b ) {\n var i, j, t, xLTy,\n x = this,\n a = x.s;\n\n id = 10;\n y = new BigNumber( y, b );\n b = y.s;\n\n // Either NaN?\n if ( !a || !b ) return new BigNumber(NaN);\n\n // Signs differ?\n if ( a != b ) {\n y.s = -b;\n return x.plus(y);\n }\n\n var xe = x.e / LOG_BASE,\n ye = y.e / LOG_BASE,\n xc = x.c,\n yc = y.c;\n\n if ( !xe || !ye ) {\n\n // Either Infinity?\n if ( !xc || !yc ) return xc ? ( y.s = -b, y ) : new BigNumber( yc ? x : NaN );\n\n // Either zero?\n if ( !xc[0] || !yc[0] ) {\n\n // Return y if y is non-zero, x if x is non-zero, or zero if both are zero.\n return yc[0] ? ( y.s = -b, y ) : new BigNumber( xc[0] ? x :\n\n // IEEE 754 (2008) 6.3: n - n = -0 when rounding to -Infinity\n ROUNDING_MODE == 3 ? -0 : 0 );\n }\n }\n\n xe = bitFloor(xe);\n ye = bitFloor(ye);\n xc = xc.slice();\n\n // Determine which is the bigger number.\n if ( a = xe - ye ) {\n\n if ( xLTy = a < 0 ) {\n a = -a;\n t = xc;\n } else {\n ye = xe;\n t = yc;\n }\n\n t.reverse();\n\n // Prepend zeros to equalise exponents.\n for ( b = a; b--; t.push(0) );\n t.reverse();\n } else {\n\n // Exponents equal. Check digit by digit.\n j = ( xLTy = ( a = xc.length ) < ( b = yc.length ) ) ? a : b;\n\n for ( a = b = 0; b < j; b++ ) {\n\n if ( xc[b] != yc[b] ) {\n xLTy = xc[b] < yc[b];\n break;\n }\n }\n }\n\n // x < y? Point xc to the array of the bigger number.\n if (xLTy) t = xc, xc = yc, yc = t, y.s = -y.s;\n\n b = ( j = yc.length ) - ( i = xc.length );\n\n // Append zeros to xc if shorter.\n // No need to add zeros to yc if shorter as subtract only needs to start at yc.length.\n if ( b > 0 ) for ( ; b--; xc[i++] = 0 );\n b = BASE - 1;\n\n // Subtract yc from xc.\n for ( ; j > a; ) {\n\n if ( xc[--j] < yc[j] ) {\n for ( i = j; i && !xc[--i]; xc[i] = b );\n --xc[i];\n xc[j] += BASE;\n }\n\n xc[j] -= yc[j];\n }\n\n // Remove leading zeros and adjust exponent accordingly.\n for ( ; xc[0] == 0; xc.shift(), --ye );\n\n // Zero?\n if ( !xc[0] ) {\n\n // Following IEEE 754 (2008) 6.3,\n // n - n = +0 but n - n = -0 when rounding towards -Infinity.\n y.s = ROUNDING_MODE == 3 ? -1 : 1;\n y.c = [ y.e = 0 ];\n return y;\n }\n\n // No need to check for Infinity as +x - +y != Infinity && -x - -y != Infinity\n // for finite x and y.\n return normalise( y, xc, ye );\n };\n\n\n /*\n * n % 0 = N\n * n % N = N\n * n % I = n\n * 0 % n = 0\n * -0 % n = -0\n * 0 % 0 = N\n * 0 % N = N\n * 0 % I = 0\n * N % n = N\n * N % 0 = N\n * N % N = N\n * N % I = N\n * I % n = N\n * I % 0 = N\n * I % N = N\n * I % I = N\n *\n * Return a new BigNumber whose value is the value of this BigNumber modulo the value of\n * BigNumber(y, b). The result depends on the value of MODULO_MODE.\n */\n P.modulo = P.mod = function ( y, b ) {\n var q, s,\n x = this;\n\n id = 11;\n y = new BigNumber( y, b );\n\n // Return NaN if x is Infinity or NaN, or y is NaN or zero.\n if ( !x.c || !y.s || y.c && !y.c[0] ) {\n return new BigNumber(NaN);\n\n // Return x if y is Infinity or x is zero.\n } else if ( !y.c || x.c && !x.c[0] ) {\n return new BigNumber(x);\n }\n\n if ( MODULO_MODE == 9 ) {\n\n // Euclidian division: q = sign(y) * floor(x / abs(y))\n // r = x - qy where 0 <= r < abs(y)\n s = y.s;\n y.s = 1;\n q = div( x, y, 0, 3 );\n y.s = s;\n q.s *= s;\n } else {\n q = div( x, y, 0, MODULO_MODE );\n }\n\n return x.minus( q.times(y) );\n };\n\n\n /*\n * Return a new BigNumber whose value is the value of this BigNumber negated,\n * i.e. multiplied by -1.\n */\n P.negated = P.neg = function () {\n var x = new BigNumber(this);\n x.s = -x.s || null;\n return x;\n };\n\n\n /*\n * n + 0 = n\n * n + N = N\n * n + I = I\n * 0 + n = n\n * 0 + 0 = 0\n * 0 + N = N\n * 0 + I = I\n * N + n = N\n * N + 0 = N\n * N + N = N\n * N + I = N\n * I + n = I\n * I + 0 = I\n * I + N = N\n * I + I = I\n *\n * Return a new BigNumber whose value is the value of this BigNumber plus the value of\n * BigNumber(y, b).\n */\n P.plus = P.add = function ( y, b ) {\n var t,\n x = this,\n a = x.s;\n\n id = 12;\n y = new BigNumber( y, b );\n b = y.s;\n\n // Either NaN?\n if ( !a || !b ) return new BigNumber(NaN);\n\n // Signs differ?\n if ( a != b ) {\n y.s = -b;\n return x.minus(y);\n }\n\n var xe = x.e / LOG_BASE,\n ye = y.e / LOG_BASE,\n xc = x.c,\n yc = y.c;\n\n if ( !xe || !ye ) {\n\n // Return ±Infinity if either ±Infinity.\n if ( !xc || !yc ) return new BigNumber( a / 0 );\n\n // Either zero?\n // Return y if y is non-zero, x if x is non-zero, or zero if both are zero.\n if ( !xc[0] || !yc[0] ) return yc[0] ? y : new BigNumber( xc[0] ? x : a * 0 );\n }\n\n xe = bitFloor(xe);\n ye = bitFloor(ye);\n xc = xc.slice();\n\n // Prepend zeros to equalise exponents. Faster to use reverse then do unshifts.\n if ( a = xe - ye ) {\n if ( a > 0 ) {\n ye = xe;\n t = yc;\n } else {\n a = -a;\n t = xc;\n }\n\n t.reverse();\n for ( ; a--; t.push(0) );\n t.reverse();\n }\n\n a = xc.length;\n b = yc.length;\n\n // Point xc to the longer array, and b to the shorter length.\n if ( a - b < 0 ) t = yc, yc = xc, xc = t, b = a;\n\n // Only start adding at yc.length - 1 as the further digits of xc can be ignored.\n for ( a = 0; b; ) {\n a = ( xc[--b] = xc[b] + yc[b] + a ) / BASE | 0;\n xc[b] %= BASE;\n }\n\n if (a) {\n xc.unshift(a);\n ++ye;\n }\n\n // No need to check for zero, as +x + +y != 0 && -x + -y != 0\n // ye = MAX_EXP + 1 possible\n return normalise( y, xc, ye );\n };\n\n\n /*\n * Return the number of significant digits of the value of this BigNumber.\n *\n * [z] {boolean|number} Whether to count integer-part trailing zeros: true, false, 1 or 0.\n */\n P.precision = P.sd = function (z) {\n var n, v,\n x = this,\n c = x.c;\n\n // 'precision() argument not a boolean or binary digit: {z}'\n if ( z != null && z !== !!z && z !== 1 && z !== 0 ) {\n if (ERRORS) raise( 13, 'argument' + notBool, z );\n if ( z != !!z ) z = null;\n }\n\n if ( !c ) return null;\n v = c.length - 1;\n n = v * LOG_BASE + 1;\n\n if ( v = c[v] ) {\n\n // Subtract the number of trailing zeros of the last element.\n for ( ; v % 10 == 0; v /= 10, n-- );\n\n // Add the number of digits of the first element.\n for ( v = c[0]; v >= 10; v /= 10, n++ );\n }\n\n if ( z && x.e + 1 > n ) n = x.e + 1;\n\n return n;\n };\n\n\n /*\n * Return a new BigNumber whose value is the value of this BigNumber rounded to a maximum of\n * dp decimal places using rounding mode rm, or to 0 and ROUNDING_MODE respectively if\n * omitted.\n *\n * [dp] {number} Decimal places. Integer, 0 to MAX inclusive.\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\n *\n * 'round() decimal places out of range: {dp}'\n * 'round() decimal places not an integer: {dp}'\n * 'round() rounding mode not an integer: {rm}'\n * 'round() rounding mode out of range: {rm}'\n */\n P.round = function ( dp, rm ) {\n var n = new BigNumber(this);\n\n if ( dp == null || isValidInt( dp, 0, MAX, 15 ) ) {\n round( n, ~~dp + this.e + 1, rm == null ||\n !isValidInt( rm, 0, 8, 15, roundingMode ) ? ROUNDING_MODE : rm | 0 );\n }\n\n return n;\n };\n\n\n /*\n * Return a new BigNumber whose value is the value of this BigNumber shifted by k places\n * (powers of 10). Shift to the right if n > 0, and to the left if n < 0.\n *\n * k {number} Integer, -MAX_SAFE_INTEGER to MAX_SAFE_INTEGER inclusive.\n *\n * If k is out of range and ERRORS is false, the result will be ±0 if k < 0, or ±Infinity\n * otherwise.\n *\n * 'shift() argument not an integer: {k}'\n * 'shift() argument out of range: {k}'\n */\n P.shift = function (k) {\n var n = this;\n return isValidInt( k, -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER, 16, 'argument' )\n\n // k < 1e+21, or truncate(k) will produce exponential notation.\n ? n.times( '1e' + truncate(k) )\n : new BigNumber( n.c && n.c[0] && ( k < -MAX_SAFE_INTEGER || k > MAX_SAFE_INTEGER )\n ? n.s * ( k < 0 ? 0 : 1 / 0 )\n : n );\n };\n\n\n /*\n * sqrt(-n) = N\n * sqrt( N) = N\n * sqrt(-I) = N\n * sqrt( I) = I\n * sqrt( 0) = 0\n * sqrt(-0) = -0\n *\n * Return a new BigNumber whose value is the square root of the value of this BigNumber,\n * rounded according to DECIMAL_PLACES and ROUNDING_MODE.\n */\n P.squareRoot = P.sqrt = function () {\n var m, n, r, rep, t,\n x = this,\n c = x.c,\n s = x.s,\n e = x.e,\n dp = DECIMAL_PLACES + 4,\n half = new BigNumber('0.5');\n\n // Negative/NaN/Infinity/zero?\n if ( s !== 1 || !c || !c[0] ) {\n return new BigNumber( !s || s < 0 && ( !c || c[0] ) ? NaN : c ? x : 1 / 0 );\n }\n\n // Initial estimate.\n s = Math.sqrt( +x );\n\n // Math.sqrt underflow/overflow?\n // Pass x to Math.sqrt as integer, then adjust the exponent of the result.\n if ( s == 0 || s == 1 / 0 ) {\n n = coeffToString(c);\n if ( ( n.length + e ) % 2 == 0 ) n += '0';\n s = Math.sqrt(n);\n e = bitFloor( ( e + 1 ) / 2 ) - ( e < 0 || e % 2 );\n\n if ( s == 1 / 0 ) {\n n = '1e' + e;\n } else {\n n = s.toExponential();\n n = n.slice( 0, n.indexOf('e') + 1 ) + e;\n }\n\n r = new BigNumber(n);\n } else {\n r = new BigNumber( s + '' );\n }\n\n // Check for zero.\n // r could be zero if MIN_EXP is changed after the this value was created.\n // This would cause a division by zero (x/t) and hence Infinity below, which would cause\n // coeffToString to throw.\n if ( r.c[0] ) {\n e = r.e;\n s = e + dp;\n if ( s < 3 ) s = 0;\n\n // Newton-Raphson iteration.\n for ( ; ; ) {\n t = r;\n r = half.times( t.plus( div( x, t, dp, 1 ) ) );\n\n if ( coeffToString( t.c ).slice( 0, s ) === ( n =\n coeffToString( r.c ) ).slice( 0, s ) ) {\n\n // The exponent of r may here be one less than the final result exponent,\n // e.g 0.0009999 (e-4) --> 0.001 (e-3), so adjust s so the rounding digits\n // are indexed correctly.\n if ( r.e < e ) --s;\n n = n.slice( s - 3, s + 1 );\n\n // The 4th rounding digit may be in error by -1 so if the 4 rounding digits\n // are 9999 or 4999 (i.e. approaching a rounding boundary) continue the\n // iteration.\n if ( n == '9999' || !rep && n == '4999' ) {\n\n // On the first iteration only, check to see if rounding up gives the\n // exact result as the nines may infinitely repeat.\n if ( !rep ) {\n round( t, t.e + DECIMAL_PLACES + 2, 0 );\n\n if ( t.times(t).eq(x) ) {\n r = t;\n break;\n }\n }\n\n dp += 4;\n s += 4;\n rep = 1;\n } else {\n\n // If rounding digits are null, 0{0,4} or 50{0,3}, check for exact\n // result. If not, then there are further digits and m will be truthy.\n if ( !+n || !+n.slice(1) && n.charAt(0) == '5' ) {\n\n // Truncate to the first rounding digit.\n round( r, r.e + DECIMAL_PLACES + 2, 1 );\n m = !r.times(r).eq(x);\n }\n\n break;\n }\n }\n }\n }\n\n return round( r, r.e + DECIMAL_PLACES + 1, ROUNDING_MODE, m );\n };\n\n\n /*\n * n * 0 = 0\n * n * N = N\n * n * I = I\n * 0 * n = 0\n * 0 * 0 = 0\n * 0 * N = N\n * 0 * I = N\n * N * n = N\n * N * 0 = N\n * N * N = N\n * N * I = N\n * I * n = I\n * I * 0 = N\n * I * N = N\n * I * I = I\n *\n * Return a new BigNumber whose value is the value of this BigNumber times the value of\n * BigNumber(y, b).\n */\n P.times = P.mul = function ( y, b ) {\n var c, e, i, j, k, m, xcL, xlo, xhi, ycL, ylo, yhi, zc,\n base, sqrtBase,\n x = this,\n xc = x.c,\n yc = ( id = 17, y = new BigNumber( y, b ) ).c;\n\n // Either NaN, ±Infinity or ±0?\n if ( !xc || !yc || !xc[0] || !yc[0] ) {\n\n // Return NaN if either is NaN, or one is 0 and the other is Infinity.\n if ( !x.s || !y.s || xc && !xc[0] && !yc || yc && !yc[0] && !xc ) {\n y.c = y.e = y.s = null;\n } else {\n y.s *= x.s;\n\n // Return ±Infinity if either is ±Infinity.\n if ( !xc || !yc ) {\n y.c = y.e = null;\n\n // Return ±0 if either is ±0.\n } else {\n y.c = [0];\n y.e = 0;\n }\n }\n\n return y;\n }\n\n e = bitFloor( x.e / LOG_BASE ) + bitFloor( y.e / LOG_BASE );\n y.s *= x.s;\n xcL = xc.length;\n ycL = yc.length;\n\n // Ensure xc points to longer array and xcL to its length.\n if ( xcL < ycL ) zc = xc, xc = yc, yc = zc, i = xcL, xcL = ycL, ycL = i;\n\n // Initialise the result array with zeros.\n for ( i = xcL + ycL, zc = []; i--; zc.push(0) );\n\n base = BASE;\n sqrtBase = SQRT_BASE;\n\n for ( i = ycL; --i >= 0; ) {\n c = 0;\n ylo = yc[i] % sqrtBase;\n yhi = yc[i] / sqrtBase | 0;\n\n for ( k = xcL, j = i + k; j > i; ) {\n xlo = xc[--k] % sqrtBase;\n xhi = xc[k] / sqrtBase | 0;\n m = yhi * xlo + xhi * ylo;\n xlo = ylo * xlo + ( ( m % sqrtBase ) * sqrtBase ) + zc[j] + c;\n c = ( xlo / base | 0 ) + ( m / sqrtBase | 0 ) + yhi * xhi;\n zc[j--] = xlo % base;\n }\n\n zc[j] = c;\n }\n\n if (c) {\n ++e;\n } else {\n zc.shift();\n }\n\n return normalise( y, zc, e );\n };\n\n\n /*\n * Return a new BigNumber whose value is the value of this BigNumber rounded to a maximum of\n * sd significant digits using rounding mode rm, or ROUNDING_MODE if rm is omitted.\n *\n * [sd] {number} Significant digits. Integer, 1 to MAX inclusive.\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\n *\n * 'toDigits() precision out of range: {sd}'\n * 'toDigits() precision not an integer: {sd}'\n * 'toDigits() rounding mode not an integer: {rm}'\n * 'toDigits() rounding mode out of range: {rm}'\n */\n P.toDigits = function ( sd, rm ) {\n var n = new BigNumber(this);\n sd = sd == null || !isValidInt( sd, 1, MAX, 18, 'precision' ) ? null : sd | 0;\n rm = rm == null || !isValidInt( rm, 0, 8, 18, roundingMode ) ? ROUNDING_MODE : rm | 0;\n return sd ? round( n, sd, rm ) : n;\n };\n\n\n /*\n * Return a string representing the value of this BigNumber in exponential notation and\n * rounded using ROUNDING_MODE to dp fixed decimal places.\n *\n * [dp] {number} Decimal places. Integer, 0 to MAX inclusive.\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\n *\n * 'toExponential() decimal places not an integer: {dp}'\n * 'toExponential() decimal places out of range: {dp}'\n * 'toExponential() rounding mode not an integer: {rm}'\n * 'toExponential() rounding mode out of range: {rm}'\n */\n P.toExponential = function ( dp, rm ) {\n return format( this,\n dp != null && isValidInt( dp, 0, MAX, 19 ) ? ~~dp + 1 : null, rm, 19 );\n };\n\n\n /*\n * Return a string representing the value of this BigNumber in fixed-point notation rounding\n * to dp fixed decimal places using rounding mode rm, or ROUNDING_MODE if rm is omitted.\n *\n * Note: as with JavaScript's number type, (-0).toFixed(0) is '0',\n * but e.g. (-0.00001).toFixed(0) is '-0'.\n *\n * [dp] {number} Decimal places. Integer, 0 to MAX inclusive.\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\n *\n * 'toFixed() decimal places not an integer: {dp}'\n * 'toFixed() decimal places out of range: {dp}'\n * 'toFixed() rounding mode not an integer: {rm}'\n * 'toFixed() rounding mode out of range: {rm}'\n */\n P.toFixed = function ( dp, rm ) {\n return format( this, dp != null && isValidInt( dp, 0, MAX, 20 )\n ? ~~dp + this.e + 1 : null, rm, 20 );\n };\n\n\n /*\n * Return a string representing the value of this BigNumber in fixed-point notation rounded\n * using rm or ROUNDING_MODE to dp decimal places, and formatted according to the properties\n * of the FORMAT object (see BigNumber.config).\n *\n * FORMAT = {\n * decimalSeparator : '.',\n * groupSeparator : ',',\n * groupSize : 3,\n * secondaryGroupSize : 0,\n * fractionGroupSeparator : '\\xA0', // non-breaking space\n * fractionGroupSize : 0\n * };\n *\n * [dp] {number} Decimal places. Integer, 0 to MAX inclusive.\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\n *\n * 'toFormat() decimal places not an integer: {dp}'\n * 'toFormat() decimal places out of range: {dp}'\n * 'toFormat() rounding mode not an integer: {rm}'\n * 'toFormat() rounding mode out of range: {rm}'\n */\n P.toFormat = function ( dp, rm ) {\n var str = format( this, dp != null && isValidInt( dp, 0, MAX, 21 )\n ? ~~dp + this.e + 1 : null, rm, 21 );\n\n if ( this.c ) {\n var i,\n arr = str.split('.'),\n g1 = +FORMAT.groupSize,\n g2 = +FORMAT.secondaryGroupSize,\n groupSeparator = FORMAT.groupSeparator,\n intPart = arr[0],\n fractionPart = arr[1],\n isNeg = this.s < 0,\n intDigits = isNeg ? intPart.slice(1) : intPart,\n len = intDigits.length;\n\n if (g2) i = g1, g1 = g2, g2 = i, len -= i;\n\n if ( g1 > 0 && len > 0 ) {\n i = len % g1 || g1;\n intPart = intDigits.substr( 0, i );\n\n for ( ; i < len; i += g1 ) {\n intPart += groupSeparator + intDigits.substr( i, g1 );\n }\n\n if ( g2 > 0 ) intPart += groupSeparator + intDigits.slice(i);\n if (isNeg) intPart = '-' + intPart;\n }\n\n str = fractionPart\n ? intPart + FORMAT.decimalSeparator + ( ( g2 = +FORMAT.fractionGroupSize )\n ? fractionPart.replace( new RegExp( '\\\\d{' + g2 + '}\\\\B', 'g' ),\n '$&' + FORMAT.fractionGroupSeparator )\n : fractionPart )\n : intPart;\n }\n\n return str;\n };\n\n\n /*\n * Return a string array representing the value of this BigNumber as a simple fraction with\n * an integer numerator and an integer denominator. The denominator will be a positive\n * non-zero value less than or equal to the specified maximum denominator. If a maximum\n * denominator is not specified, the denominator will be the lowest value necessary to\n * represent the number exactly.\n *\n * [md] {number|string|BigNumber} Integer >= 1 and < Infinity. The maximum denominator.\n *\n * 'toFraction() max denominator not an integer: {md}'\n * 'toFraction() max denominator out of range: {md}'\n */\n P.toFraction = function (md) {\n var arr, d0, d2, e, exp, n, n0, q, s,\n k = ERRORS,\n x = this,\n xc = x.c,\n d = new BigNumber(ONE),\n n1 = d0 = new BigNumber(ONE),\n d1 = n0 = new BigNumber(ONE);\n\n if ( md != null ) {\n ERRORS = false;\n n = new BigNumber(md);\n ERRORS = k;\n\n if ( !( k = n.isInt() ) || n.lt(ONE) ) {\n\n if (ERRORS) {\n raise( 22,\n 'max denominator ' + ( k ? 'out of range' : 'not an integer' ), md );\n }\n\n // ERRORS is false:\n // If md is a finite non-integer >= 1, round it to an integer and use it.\n md = !k && n.c && round( n, n.e + 1, 1 ).gte(ONE) ? n : null;\n }\n }\n\n if ( !xc ) return x.toString();\n s = coeffToString(xc);\n\n // Determine initial denominator.\n // d is a power of 10 and the minimum max denominator that specifies the value exactly.\n e = d.e = s.length - x.e - 1;\n d.c[0] = POWS_TEN[ ( exp = e % LOG_BASE ) < 0 ? LOG_BASE + exp : exp ];\n md = !md || n.cmp(d) > 0 ? ( e > 0 ? d : n1 ) : n;\n\n exp = MAX_EXP;\n MAX_EXP = 1 / 0;\n n = new BigNumber(s);\n\n // n0 = d1 = 0\n n0.c[0] = 0;\n\n for ( ; ; ) {\n q = div( n, d, 0, 1 );\n d2 = d0.plus( q.times(d1) );\n if ( d2.cmp(md) == 1 ) break;\n d0 = d1;\n d1 = d2;\n n1 = n0.plus( q.times( d2 = n1 ) );\n n0 = d2;\n d = n.minus( q.times( d2 = d ) );\n n = d2;\n }\n\n d2 = div( md.minus(d0), d1, 0, 1 );\n n0 = n0.plus( d2.times(n1) );\n d0 = d0.plus( d2.times(d1) );\n n0.s = n1.s = x.s;\n e *= 2;\n\n // Determine which fraction is closer to x, n0/d0 or n1/d1\n arr = div( n1, d1, e, ROUNDING_MODE ).minus(x).abs().cmp(\n div( n0, d0, e, ROUNDING_MODE ).minus(x).abs() ) < 1\n ? [ n1.toString(), d1.toString() ]\n : [ n0.toString(), d0.toString() ];\n\n MAX_EXP = exp;\n return arr;\n };\n\n\n /*\n * Return the value of this BigNumber converted to a number primitive.\n */\n P.toNumber = function () {\n var x = this;\n\n // Ensure zero has correct sign.\n return +x || ( x.s ? x.s * 0 : NaN );\n };\n\n\n /*\n * Return a BigNumber whose value is the value of this BigNumber raised to the power n.\n * If n is negative round according to DECIMAL_PLACES and ROUNDING_MODE.\n * If POW_PRECISION is not 0, round to POW_PRECISION using ROUNDING_MODE.\n *\n * n {number} Integer, -9007199254740992 to 9007199254740992 inclusive.\n * (Performs 54 loop iterations for n of 9007199254740992.)\n *\n * 'pow() exponent not an integer: {n}'\n * 'pow() exponent out of range: {n}'\n */\n P.toPower = P.pow = function (n) {\n var k, y,\n i = mathfloor( n < 0 ? -n : +n ),\n x = this;\n\n // Pass ±Infinity to Math.pow if exponent is out of range.\n if ( !isValidInt( n, -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER, 23, 'exponent' ) &&\n ( !isFinite(n) || i > MAX_SAFE_INTEGER && ( n /= 0 ) ||\n parseFloat(n) != n && !( n = NaN ) ) ) {\n return new BigNumber( Math.pow( +x, n ) );\n }\n\n // Truncating each coefficient array to a length of k after each multiplication equates\n // to truncating significant digits to POW_PRECISION + [28, 41], i.e. there will be a\n // minimum of 28 guard digits retained. (Using + 1.5 would give [9, 21] guard digits.)\n k = POW_PRECISION ? mathceil( POW_PRECISION / LOG_BASE + 2 ) : 0;\n y = new BigNumber(ONE);\n\n for ( ; ; ) {\n\n if ( i % 2 ) {\n y = y.times(x);\n if ( !y.c ) break;\n if ( k && y.c.length > k ) y.c.length = k;\n }\n\n i = mathfloor( i / 2 );\n if ( !i ) break;\n\n x = x.times(x);\n if ( k && x.c && x.c.length > k ) x.c.length = k;\n }\n\n if ( n < 0 ) y = ONE.div(y);\n return k ? round( y, POW_PRECISION, ROUNDING_MODE ) : y;\n };\n\n\n /*\n * Return a string representing the value of this BigNumber rounded to sd significant digits\n * using rounding mode rm or ROUNDING_MODE. If sd is less than the number of digits\n * necessary to represent the integer part of the value in fixed-point notation, then use\n * exponential notation.\n *\n * [sd] {number} Significant digits. Integer, 1 to MAX inclusive.\n * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive.\n *\n * 'toPrecision() precision not an integer: {sd}'\n * 'toPrecision() precision out of range: {sd}'\n * 'toPrecision() rounding mode not an integer: {rm}'\n * 'toPrecision() rounding mode out of range: {rm}'\n */\n P.toPrecision = function ( sd, rm ) {\n return format( this, sd != null && isValidInt( sd, 1, MAX, 24, 'precision' )\n ? sd | 0 : null, rm, 24 );\n };\n\n\n /*\n * Return a string representing the value of this BigNumber in base b, or base 10 if b is\n * omitted. If a base is specified, including base 10, round according to DECIMAL_PLACES and\n * ROUNDING_MODE. If a base is not specified, and this BigNumber has a positive exponent\n * that is equal to or greater than TO_EXP_POS, or a negative exponent equal to or less than\n * TO_EXP_NEG, return exponential notation.\n *\n * [b] {number} Integer, 2 to 64 inclusive.\n *\n * 'toString() base not an integer: {b}'\n * 'toString() base out of range: {b}'\n */\n P.toString = function (b) {\n var str,\n n = this,\n s = n.s,\n e = n.e;\n\n // Infinity or NaN?\n if ( e === null ) {\n\n if (s) {\n str = 'Infinity';\n if ( s < 0 ) str = '-' + str;\n } else {\n str = 'NaN';\n }\n } else {\n str = coeffToString( n.c );\n\n if ( b == null || !isValidInt( b, 2, 64, 25, 'base' ) ) {\n str = e <= TO_EXP_NEG || e >= TO_EXP_POS\n ? toExponential( str, e )\n : toFixedPoint( str, e );\n } else {\n str = convertBase( toFixedPoint( str, e ), b | 0, 10, s );\n }\n\n if ( s < 0 && n.c[0] ) str = '-' + str;\n }\n\n return str;\n };\n\n\n /*\n * Return a new BigNumber whose value is the value of this BigNumber truncated to a whole\n * number.\n */\n P.truncated = P.trunc = function () {\n return round( new BigNumber(this), this.e + 1, 1 );\n };\n\n\n\n /*\n * Return as toString, but do not accept a base argument.\n */\n P.valueOf = P.toJSON = function () {\n return this.toString();\n };\n\n\n // Aliases for BigDecimal methods.\n //P.add = P.plus; // P.add included above\n //P.subtract = P.minus; // P.sub included above\n //P.multiply = P.times; // P.mul included above\n //P.divide = P.div;\n //P.remainder = P.mod;\n //P.compareTo = P.cmp;\n //P.negate = P.neg;\n\n\n if ( configObj != null ) BigNumber.config(configObj);\n\n return BigNumber;\n }\n\n\n // PRIVATE HELPER FUNCTIONS\n\n\n function bitFloor(n) {\n var i = n | 0;\n return n > 0 || n === i ? i : i - 1;\n }\n\n\n // Return a coefficient array as a string of base 10 digits.\n function coeffToString(a) {\n var s, z,\n i = 1,\n j = a.length,\n r = a[0] + '';\n\n for ( ; i < j; ) {\n s = a[i++] + '';\n z = LOG_BASE - s.length;\n for ( ; z--; s = '0' + s );\n r += s;\n }\n\n // Determine trailing zeros.\n for ( j = r.length; r.charCodeAt(--j) === 48; );\n return r.slice( 0, j + 1 || 1 );\n }\n\n\n // Compare the value of BigNumbers x and y.\n function compare( x, y ) {\n var a, b,\n xc = x.c,\n yc = y.c,\n i = x.s,\n j = y.s,\n k = x.e,\n l = y.e;\n\n // Either NaN?\n if ( !i || !j ) return null;\n\n a = xc && !xc[0];\n b = yc && !yc[0];\n\n // Either zero?\n if ( a || b ) return a ? b ? 0 : -j : i;\n\n // Signs differ?\n if ( i != j ) return i;\n\n a = i < 0;\n b = k == l;\n\n // Either Infinity?\n if ( !xc || !yc ) return b ? 0 : !xc ^ a ? 1 : -1;\n\n // Compare exponents.\n if ( !b ) return k > l ^ a ? 1 : -1;\n\n j = ( k = xc.length ) < ( l = yc.length ) ? k : l;\n\n // Compare digit by digit.\n for ( i = 0; i < j; i++ ) if ( xc[i] != yc[i] ) return xc[i] > yc[i] ^ a ? 1 : -1;\n\n // Compare lengths.\n return k == l ? 0 : k > l ^ a ? 1 : -1;\n }\n\n\n /*\n * Return true if n is a valid number in range, otherwise false.\n * Use for argument validation when ERRORS is false.\n * Note: parseInt('1e+1') == 1 but parseFloat('1e+1') == 10.\n */\n function intValidatorNoErrors( n, min, max ) {\n return ( n = truncate(n) ) >= min && n <= max;\n }\n\n\n function isArray(obj) {\n return Object.prototype.toString.call(obj) == '[object Array]';\n }\n\n\n /*\n * Convert string of baseIn to an array of numbers of baseOut.\n * Eg. convertBase('255', 10, 16) returns [15, 15].\n * Eg. convertBase('ff', 16, 10) returns [2, 5, 5].\n */\n function toBaseOut( str, baseIn, baseOut ) {\n var j,\n arr = [0],\n arrL,\n i = 0,\n len = str.length;\n\n for ( ; i < len; ) {\n for ( arrL = arr.length; arrL--; arr[arrL] *= baseIn );\n arr[ j = 0 ] += ALPHABET.indexOf( str.charAt( i++ ) );\n\n for ( ; j < arr.length; j++ ) {\n\n if ( arr[j] > baseOut - 1 ) {\n if ( arr[j + 1] == null ) arr[j + 1] = 0;\n arr[j + 1] += arr[j] / baseOut | 0;\n arr[j] %= baseOut;\n }\n }\n }\n\n return arr.reverse();\n }\n\n\n function toExponential( str, e ) {\n return ( str.length > 1 ? str.charAt(0) + '.' + str.slice(1) : str ) +\n ( e < 0 ? 'e' : 'e+' ) + e;\n }\n\n\n function toFixedPoint( str, e ) {\n var len, z;\n\n // Negative exponent?\n if ( e < 0 ) {\n\n // Prepend zeros.\n for ( z = '0.'; ++e; z += '0' );\n str = z + str;\n\n // Positive exponent\n } else {\n len = str.length;\n\n // Append zeros.\n if ( ++e > len ) {\n for ( z = '0', e -= len; --e; z += '0' );\n str += z;\n } else if ( e < len ) {\n str = str.slice( 0, e ) + '.' + str.slice(e);\n }\n }\n\n return str;\n }\n\n\n function truncate(n) {\n n = parseFloat(n);\n return n < 0 ? mathceil(n) : mathfloor(n);\n }\n\n\n // EXPORT\n\n\n BigNumber = another();\n\n // AMD.\n if ( typeof define == 'function' && define.amd ) {\n define( function () { return BigNumber; } );\n\n // Node and other environments that support module.exports.\n } else if ( typeof module != 'undefined' && module.exports ) {\n module.exports = BigNumber;\n if ( !crypto ) try { crypto = require('crypto'); } catch (e) {}\n\n // Browser.\n } else {\n global.BigNumber = BigNumber;\n }\n})(this);\n", - "var web3 = require('./lib/web3');\nweb3.providers.HttpProvider = require('./lib/web3/httpprovider');\nweb3.providers.QtSyncProvider = require('./lib/web3/qtsync');\nweb3.eth.contract = require('./lib/web3/contract');\n\n// dont override global variable\nif (typeof window !== 'undefined' && typeof window.web3 === 'undefined') {\n window.web3 = web3;\n}\n\nmodule.exports = web3;\n\n" - ] -} \ No newline at end of file diff --git a/libjsqrc/ethereumjs/dist/web3.min.js b/libjsqrc/ethereumjs/dist/web3.min.js index eb4052b6c..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 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 l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n?n:t)},l,l.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 l=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=l},{"../utils/utils":6,"./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)},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)},m=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)},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))},g=function(t){return h(t).dividedBy(new r(2).pow(128))},y=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:l,formatInputReal:f,formatOutputInt:m,formatOutputUInt:h,formatOutputReal:d,formatOutputUReal:g,formatOutputBool:y,formatOutputBytes:v,formatOutputDynamicBytes:b,formatOutputAddress:w}},{"../utils/config":5,"../utils/utils":6,"./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},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))},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)))},e.exports=o},{"../utils/utils":6}],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","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("bignumber.js"),o={wei:"1",kwei:"1000",ada:"1000",mwei:"1000000",babbage:"1000000",gwei:"1000000000",shannon:"1000000000",szabo:"1000000000000",finney:"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},a.prototype.signature=function(){return r.sha3(r.fromAscii(this._name)).slice(2,10)},a.prototype.unpackOutput=function(t){if(null!==t){t=t.length>=2?t.slice(2):t;var e=o.decodeParams(this._outputTypes,t);return 1===e.length?e[0]:e}},a.prototype.call=function(){var t=Array.prototype.slice.call(arguments),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))})},a.prototype.sendTransaction=function(){var t=Array.prototype.slice.call(arguments),e=this.extractCallback(t),n=this.toPayload(t);return e?void r.eth.sendTransaction(n,e):void r.eth.sendTransaction(n)},a.prototype.displayName=function(){return i.extractDisplayName(this._name)},a.prototype.typeName=function(){return i.extractTypeName(this._name)},a.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}},a.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))},a.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);var n=this.displayName();t[n]||(t[n]=e),t[n][this.typeName()]=e},e.exports=a},{"../solidity/coder":1,"../utils/utils":6,"../web3":8}],18:[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":12,xmlhttprequest:4}],19:[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},{}],20:[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":6,"./errors":12,"./requestmanager":24}],21:[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":6,"./property":22}],22:[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":24}],23:[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},{}],24:[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":6,"./errors":12,"./jsonrpc":19}],25:[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}),l=[i,a,s,u,c];e.exports={methods:l}},{"./formatters":16,"./method":20}],26:[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":20}],27:[function(t,e,n){},{}],"bignumber.js":[function(t,e,n){!function(n){"use strict";function r(t){function e(t,r){var o,i,a,s,u,c,l=this;if(!(l instanceof e))return W&&D(26,"constructor call without new",t),new e(t,r);if(null!=r&&J(r,2,64,R,"base")){if(r=0|r,c=t+"",10==r)return l=new e(t instanceof e?t:c),S(l,L+l.e+1,U);if((s="number"==typeof t)&&0*t!=0||!new RegExp("^-?"+(o="["+F.slice(0,r)+"]+")+"(?:\\."+o+")?$",37>r?"i":"").test(c))return d(l,c,s,r);s?(l.s=0>1/t?(c=c.slice(1),-1):1,W&&c.replace(/^0\.0*|\./,"").length>15&&D(R,_,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(R=0);if((s="number"==typeof t)&&0*t==0){if(l.s=0>1/t?(t=-t,-1):1,t===~~t){for(i=0,a=t;a>=10;a/=10,i++);return l.e=i,l.c=[t],void(R=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((i=c.indexOf("."))>-1&&(c=c.replace(".","")),(a=c.search(/e/i))>0?(0>i&&(i=a),i+=+c.slice(a+1),c=c.substring(0,a)):0>i&&(i=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&&W&&u>15&&D(R,_,l.s*t),i=i-a-1,i>G)l.c=l.e=null;else if(M>i)l.c=[l.e=0];else{if(l.e=i,l.c=[],a=(i+1)%I,0>i&&(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];R=0}function n(t,n,r,o){var a,s,u,l,p,m,h,d=t.indexOf("."),g=L,y=U;for(37>r&&(t=t.toLowerCase()),d>=0&&(u=z,z=0,t=t.replace(".",""),h=new e(r),p=h.pow(t.length-d),z=u,h.c=c(f(i(p.c),p.e),10,n),h.e=h.c.length),m=c(t,r,n),s=u=m.length;0==m[--u];m.pop());if(!m[0])return"0";if(0>d?--s:(p.c=m,p.e=s,p.s=o,p=E(p,h,g,y,n),m=p.c,l=p.r,s=p.e),a=s+g+1,d=m[a],u=n/2,l=l||0>a||null!=m[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&m[a-1]||y==(p.s<0?8:7)),1>a||!m[0])t=l?f("1",-g):"0";else{if(m.length=a,l)for(--n;++m[--a]>n;)m[a]=0,a||(++s,m.unshift(1));for(u=m.length;!m[--u];);for(d=0,t="";u>=d;t+=F.charAt(m[d++]));t=f(t,s)}return t}function m(t,n,r,o){var a,s,u,c,p;if(r=null!=r&&J(r,0,8,o,w)?0|r:U,!t.c)return t.toString();if(a=t.c[0],u=t.e,null==n)p=i(t.c),p=19==o||24==o&&j>=u?l(p,u):f(p,u);else if(t=S(new e(t),n,r),s=t.e,p=i(t.c),c=p.length,19==o||24==o&&(s>=n||j>=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 T(t,n){var r,o,i=0;for(u(t[0])&&(t=t[0]),r=new e(t[0]);++it||t>n||t!=p(t))&&D(r,(o||"decimal places")+(e>t||t>n?" out of range":" not an integer"),t),!0}function k(t,e,n){for(var r=1,o=e.length;!e[--o];e.pop());for(o=e[0];o>=10;o/=10,r++);return(n=r+n*I-1)>G?t.c=t.e=null:M>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",R=0,r}function S(t,e,n,r){var o,i,a,s,u,c,l,f=t.c,p=O;if(f){t:{for(o=1,s=f[0];s>=10;s/=10,o++);if(i=e-o,0>i)i+=I,a=e,u=f[c=0],l=u/p[o-a-1]%10|0;else if(c=y((i+1)/I),c>=f.length){if(!r)break t;for(;f.length<=c;f.push(0));u=l=0,o=1,i%=I,a=i-I+1}else{for(u=s=f[c],o=1;s>=10;s/=10,o++);i%=I,a=i-I+o,l=0>a?0:u/p[o-a-1]%10|0}if(r=r||0>e||null!=f[c+1]||(0>a?u:u%p[o-a-1]),r=4>n?(l||r)&&(0==n||n==(t.s<0?3:2)):l>5||5==l&&(4==n||r||6==n&&(i>0?a>0?u/p[o-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==i?(f.length=c,s=1,c--):(f.length=c+1,s=p[I-i],f[c]=a>0?v(u/p[o-a]%p[a])*s:0),r)for(;;){if(0==c){for(i=1,a=f[0];a>=10;a/=10,i++);for(a=f[0]+=s,s=1;a>=10;a/=10,s++);i!=s&&(t.e++,f[0]==x&&(f[0]=1));break}if(f[c]+=s,f[c]!=x)break;f[c--]=0,s=1}for(i=f.length;0===f[--i];f.pop());}t.e>G?t.c=t.e=null:t.en?null!=(t=o[n++]):void 0};return a(e="DECIMAL_PLACES")&&J(t,0,P,2,e)&&(L=0|t),r[e]=L,a(e="ROUNDING_MODE")&&J(t,0,8,2,e)&&(U=0|t),r[e]=U,a(e="EXPONENTIAL_AT")&&(u(t)?J(t[0],-P,0,2,e)&&J(t[1],0,P,2,e)&&(j=0|t[0],H=0|t[1]):J(t,-P,P,2,e)&&(j=-(H=0|(0>t?-t:t)))),r[e]=[j,H],a(e="RANGE")&&(u(t)?J(t[0],-P,-1,2,e)&&J(t[1],1,P,2,e)&&(M=0|t[0],G=0|t[1]):J(t,-P,P,2,e)&&(0|t?M=-(G=0|(0>t?-t:t)):W&&D(2,e+" cannot be zero",t))),r[e]=[M,G],a(e="ERRORS")&&(t===!!t||1===t||0===t?(R=0,J=(W=!!t)?A:s):W&&D(2,e+b,t)),r[e]=W,a(e="CRYPTO")&&(t===!!t||1===t||0===t?(V=!(!t||!h||"object"!=typeof h),t&&!V&&W&&D(2,"crypto unavailable",h)):W&&D(2,e+b,t)),r[e]=V,a(e="MODULO_MODE")&&J(t,0,9,2,e)&&($=0|t),r[e]=$,a(e="POW_PRECISION")&&J(t,0,P,2,e)&&(z=0|t),r[e]=z,a(e="FORMAT")&&("object"==typeof t?X=t:W&&D(2,e+" not an object",t)),r[e]=X,r},e.max=function(){return T(arguments,C.lt)},e.min=function(){return T(arguments,C.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,o,i,a,s,u=0,c=[],l=new e(q);if(t=null!=t&&J(t,0,P,14)?0|t:L,a=y(t/I),V)if(h&&h.getRandomValues){for(r=h.getRandomValues(new Uint32Array(a*=2));a>u;)s=131072*r[u]+(r[u+1]>>>11),s>=9e15?(o=h.getRandomValues(new Uint32Array(2)),r[u]=o[0],r[u+1]=o[1]):(c.push(s%1e14),u+=2);u=a/2}else if(h&&h.randomBytes){for(r=h.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?h.randomBytes(7).copy(r,u):(c.push(s%1e14),u+=7);u=a/7}else W&&D(14,"crypto unavailable",h);if(!u)for(;a>u;)s=n(),9e15>s&&(c[u++]=s%1e14);for(a=c[--u],t%=I,a&&t&&(s=O[I-t],c[u]=v(a/s)*s);0===c[u];c.pop(),u--);if(0>u)c=[i=0];else{for(i=-1;0===c[0];c.shift(),i-=I);for(u=1,s=c[0];s>=10;s/=10,u++);I>u&&(i-=I-u)}return l.e=i,l.c=c,l}}(),E=function(){function t(t,e,n){var r,o,i,a,s=0,u=t.length,c=e%B,l=e/B|0;for(t=t.slice();u--;)i=t[u]%B,a=t[u]/B|0,r=l*i+a*c,o=c*i+r%B*B+s,s=(o/n|0)+(r/B|0)+l*a,t[u]=o%n;return s&&t.unshift(s),t}function n(t,e,n,r){var o,i;if(n!=r)i=n>r?1:-1;else for(o=i=0;n>o;o++)if(t[o]!=e[o]){i=t[o]>e[o]?1:-1;break}return i}function r(t,e,n,r){for(var o=0;n--;)t[n]-=o,o=t[n]1;t.shift());}return function(i,a,s,u,c){var l,f,p,m,h,d,g,y,b,w,_,F,N,O,B,P,T,A=i.s==a.s?1:-1,k=i.c,D=a.c;if(!(k&&k[0]&&D&&D[0]))return new e(i.s&&a.s&&(k?!D||k[0]!=D[0]:D)?k&&0==k[0]||!D?0*A:A/0:0/0);for(y=new e(A),b=y.c=[],f=i.e-a.e,A=s+f+1,c||(c=x,f=o(i.e/I)-o(a.e/I),A=A/I|0),p=0;D[p]==(k[p]||0);p++);if(D[p]>(k[p]||0)&&f--,0>A)b.push(1),m=!0;else{for(O=k.length,P=D.length,p=0,A+=2,h=v(c/(D[0]+1)),h>1&&(D=t(D,h,c),k=t(k,h,c),P=D.length,O=k.length),N=P,w=k.slice(0,P),_=w.length;P>_;w[_++]=0);T=D.slice(),T.unshift(0),B=D[0],D[1]>=c/2&&B++;do{if(h=0,l=n(D,w,P,_),0>l){if(F=w[0],P!=_&&(F=F*c+(w[1]||0)),h=v(F/B),h>1)for(h>=c&&(h=c-1),d=t(D,h,c),g=d.length,_=w.length;1==n(d,w,g,_);)h--,r(d,g>P?T:D,g,c),g=d.length,l=1;else 0==h&&(l=h=1),d=D.slice(),g=d.length;if(_>g&&d.unshift(0),r(w,d,_,c),_=w.length,-1==l)for(;n(D,w,P,_)<1;)h++,r(w,_>P?T:D,_,c),_=w.length}else 0===l&&(h++,w=[0]);b[p++]=h,w[0]?w[_++]=k[N]||0:(w=[k[N]],_=1)}while((N++=10;A/=10,p++);S(y,s+(y.e=p+f*I-1)+1,u,m)}else y.e=f,y.r=+m;return y}}(),d=function(){var t=/^(-?)0([xbo])/i,n=/^([^.]+)\.$/,r=/^\.([^.]+)$/,o=/^-?(Infinity|NaN)$/,i=/^\s*\+|^\s+|\s+$/g;return function(a,s,u,c){var l,f=u?s:s.replace(i,"");if(o.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);W&&D(R,"not a"+(c?" base "+c:"")+" number",s),a.s=null}a.c=a.e=null,R=0}}(),C.absoluteValue=C.abs=function(){var t=new e(this);return t.s<0&&(t.s=1),t},C.ceil=function(){return S(new e(this),this.e+1,2)},C.comparedTo=C.cmp=function(t,n){return R=1,a(this,new e(t,n))},C.decimalPlaces=C.dp=function(){var t,e,n=this.c;if(!n)return null;if(t=((e=n.length-1)-o(this.e/I))*I,e=n[e])for(;e%10==0;e/=10,t--);return 0>t&&(t=0),t},C.dividedBy=C.div=function(t,n){return R=3,E(this,new e(t,n),L,U)},C.dividedToIntegerBy=C.divToInt=function(t,n){return R=4,E(this,new e(t,n),0,1)},C.equals=C.eq=function(t,n){return R=5,0===a(this,new e(t,n))},C.floor=function(){return S(new e(this),this.e+1,3)},C.greaterThan=C.gt=function(t,n){return R=6,a(this,new e(t,n))>0},C.greaterThanOrEqualTo=C.gte=function(t,n){return R=7,1===(n=a(this,new e(t,n)))||0===n},C.isFinite=function(){return!!this.c},C.isInteger=C.isInt=function(){return!!this.c&&o(this.e/I)>this.c.length-2},C.isNaN=function(){return!this.s},C.isNegative=C.isNeg=function(){return this.s<0},C.isZero=function(){return!!this.c&&0==this.c[0]},C.lessThan=C.lt=function(t,n){return R=8,a(this,new e(t,n))<0},C.lessThanOrEqualTo=C.lte=function(t,n){return R=9,-1===(n=a(this,new e(t,n)))||0===n},C.minus=C.sub=function(t,n){var r,i,a,s,u=this,c=u.s;if(R=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,m=t.c;if(!l||!f){if(!p||!m)return p?(t.s=-n,t):new e(m?u:0/0);if(!p[0]||!m[0])return m[0]?(t.s=-n,t):new e(p[0]?u:3==U?-0:0)}if(l=o(l),f=o(f),p=p.slice(),c=l-f){for((s=0>c)?(c=-c,a=p):(f=l,a=m),a.reverse(),n=c;n--;a.push(0));a.reverse()}else for(i=(s=(c=p.length)<(n=m.length))?c:n,c=n=0;i>n;n++)if(p[n]!=m[n]){s=p[n]0)for(;n--;p[r++]=0);for(n=x-1;i>c;){if(p[--i]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)/x|0,c[n]%=x;return a&&(c.unshift(a),++u),k(t,c,u)},C.precision=C.sd=function(t){var e,n,r=this,o=r.c;if(null!=t&&t!==!!t&&1!==t&&0!==t&&(W&&D(13,"argument"+b,t),t!=!!t&&(t=null)),!o)return null;if(n=o.length-1,e=n*I+1,n=o[n]){for(;n%10==0;n/=10,e--);for(n=o[0];n>=10;n/=10,e++);}return t&&r.e+1>e&&(e=r.e+1),e},C.round=function(t,n){var r=new e(this);return(null==t||J(t,0,P,15))&&S(r,~~t+this.e+1,null!=n&&J(n,0,8,15,w)?0|n:U),r},C.shift=function(t){var n=this;return J(t,-N,N,16,"argument")?n.times("1e"+p(t)):new e(n.c&&n.c[0]&&(-N>t||t>N)?n.s*(0>t?0:1/0):n)},C.squareRoot=C.sqrt=function(){var t,n,r,a,s,u=this,c=u.c,l=u.s,f=u.e,p=L+4,m=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=i(c),(n.length+f)%2==0&&(n+="0"),l=Math.sqrt(n),f=o((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=m.times(s.plus(E(u,s,p,1))),i(s.c).slice(0,l)===(n=i(r.c)).slice(0,l)){if(r.el&&(g=w,w=_,_=g,a=l,l=m,m=a),a=l+m,g=[];a--;g.push(0));for(y=x,v=B,a=m;--a>=0;){for(r=0,h=_[a]%v,d=_[a]/v|0,u=l,s=a+u;s>a;)f=w[--u]%v,p=w[u]/v|0,c=d*f+p*h,f=h*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?++i:g.shift(),k(t,g,i)},C.toDigits=function(t,n){var r=new e(this);return t=null!=t&&J(t,1,P,18,"precision")?0|t:null,n=null!=n&&J(n,0,8,18,w)?0|n:U,t?S(r,t,n):r},C.toExponential=function(t,e){return m(this,null!=t&&J(t,0,P,19)?~~t+1:null,e,19)},C.toFixed=function(t,e){return m(this,null!=t&&J(t,0,P,20)?~~t+this.e+1:null,e,20)},C.toFormat=function(t,e){var n=m(this,null!=t&&J(t,0,P,21)?~~t+this.e+1:null,e,21);if(this.c){var r,o=n.split("."),i=+X.groupSize,a=+X.secondaryGroupSize,s=X.groupSeparator,u=o[0],c=o[1],l=this.s<0,f=l?u.slice(1):u,p=f.length;if(a&&(r=i,i=a,a=r,p-=r),i>0&&p>0){for(r=p%i||i,u=f.substr(0,r);p>r;r+=i)u+=s+f.substr(r,i);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},C.toFraction=function(t){var n,r,o,a,s,u,c,l,f,p=W,m=this,h=m.c,d=new e(q),g=r=new e(q),y=c=new e(q);if(null!=t&&(W=!1,u=new e(t),W=p,(!(p=u.isInt())||u.lt(q))&&(W&&D(22,"max denominator "+(p?"out of range":"not an integer"),t),t=!p&&u.c&&S(u,u.e+1,1).gte(q)?u:null)),!h)return m.toString();for(f=i(h),a=d.e=f.length-m.e-1,d.c[0]=O[(s=a%I)<0?I+s:s],t=!t||u.cmp(d)>0?a>0?d:g:u,s=G,G=1/0,u=new e(f),c.c[0]=0;l=E(u,d,0,1),o=r.plus(l.times(y)),1!=o.cmp(t);)r=y,y=o,g=c.plus(l.times(o=g)),c=o,d=u.minus(l.times(o=d)),u=o;return o=E(t.minus(r),y,0,1),c=c.plus(o.times(g)),r=r.plus(o.times(y)),c.s=g.s=m.s,a*=2,n=E(g,y,a,U).minus(m).abs().cmp(E(c,r,a,U).minus(m).abs())<1?[g.toString(),y.toString()]:[c.toString(),r.toString()],G=s,n},C.toNumber=function(){var t=this;return+t||(t.s?0*t.s:0/0)},C.toPower=C.pow=function(t){var n,r,o=v(0>t?-t:+t),i=this;if(!J(t,-N,N,23,"exponent")&&(!isFinite(t)||o>N&&(t/=0)||parseFloat(t)!=t&&!(t=0/0)))return new e(Math.pow(+i,t));for(n=z?y(z/I+2):0,r=new e(q);;){if(o%2){if(r=r.times(i),!r.c)break;n&&r.c.length>n&&(r.c.length=n)}if(o=v(o/2),!o)break;i=i.times(i),n&&i.c&&i.c.length>n&&(i.c.length=n)}return 0>t&&(r=q.div(r)),n?S(r,z,U):r},C.toPrecision=function(t,e){return m(this,null!=t&&J(t,1,P,24,"precision")?0|t:null,e,24)},C.toString=function(t){var e,r=this,o=r.s,a=r.e;return null===a?o?(e="Infinity",0>o&&(e="-"+e)):e="NaN":(e=i(r.c),e=null!=t&&J(t,2,64,25,"base")?n(f(e,a),0|t,10,o):j>=a||a>=H?l(e,a):f(e,a),0>o&&r.c[0]&&(e="-"+e)),e},C.truncated=C.trunc=function(){return S(new e(this),this.e+1,1)},C.valueOf=C.toJSON=function(){return this.toString()},null!=t&&e.config(t),e}function o(t){var e=0|t;return t>0||t===e?e:e-1}function i(t){for(var e,n,r=1,o=t.length,i=t[0]+"";o>r;){for(e=t[r++]+"",n=I-e.length;n--;e="0"+e);i+=e}for(o=i.length;48===i.charCodeAt(--o););return i.slice(0,o+1||1)}function a(t,e){var n,r,o=t.c,i=e.c,a=t.s,s=e.s,u=t.e,c=e.e;if(!a||!s)return null;if(n=o&&!o[0],r=i&&!i[0],n||r)return n?r?0:-s:a;if(a!=s)return a;if(n=0>a,r=u==c,!o||!i)return r?0:!o^n?1:-1;if(!r)return u>c^n?1:-1;for(s=(u=o.length)<(c=i.length)?u:c,a=0;s>a;a++)if(o[a]!=i[a])return o[a]>i[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,o,i=[0],a=0,s=t.length;s>a;){for(o=i.length;o--;i[o]*=e);for(i[r=0]+=F.indexOf(t.charAt(a++));rn-1&&(null==i[r+1]&&(i[r+1]=0),i[r+1]+=i[r]/n|0,i[r]%=n)}return i.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 m,h,d,g=/^-?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,y=Math.ceil,v=Math.floor,b=" not a boolean or binary digit",w="rounding mode",_="number type has more than 15 significant digits",F="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_",x=1e14,I=14,N=9007199254740991,O=[1,10,100,1e3,1e4,1e5,1e6,1e7,1e8,1e9,1e10,1e11,1e12,1e13],B=1e7,P=1e9;if(m=r(),"function"==typeof define&&define.amd)define(function(){return m});else if("undefined"!=typeof e&&e.exports){if(e.exports=m,!h)try{h=t("crypto")}catch(T){}}else n.BigNumber=m}(this)},{crypto:27}],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"),"undefined"!=typeof window&&"undefined"==typeof window.web3&&(window.web3=r),e.exports=r},{"./lib/web3":8,"./lib/web3/contract":10,"./lib/web3/httpprovider":18,"./lib/web3/qtsync":23}]},{},["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/example/contract.html b/libjsqrc/ethereumjs/example/contract.html index 3b83d37b1..af7546fc7 100644 --- a/libjsqrc/ethereumjs/example/contract.html +++ b/libjsqrc/ethereumjs/example/contract.html @@ -16,23 +16,10 @@ " }\n" + "}\n"; - var code = web3.eth.compile.solidity(source).code; - /*var code = "605280600c6000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063c6888fa114602e57005b60376004356041565b8060005260206000f35b6000600782029050604d565b91905056";*/ - - // contract description, this is autogenerated using solc CLI - var desc = [{ - "constant" : true, - "inputs" : [{ - "name" : "a", - "type" : "uint256" - }], - "name" : "multiply", - "outputs" : [{ - "name" : "d", - "type" : "uint256" - }], - "type" : "function" - }]; + var compiled = web3.eth.compile.solidity(source); + var code = compiled.test.code; + // contract json abi, this is autogenerated using solc CLI + var abi = compiled.test.info.abiDefinition; var myContract; @@ -47,7 +34,7 @@ var watch = web3.eth.filter('latest'); // create contract - myContract = web3.eth.contract(desc).new({data: code}); + myContract = web3.eth.contract(abi).new({data: code}); console.log('address: ' + myContract.address); document.getElementById('status').innerText = "transaction sent, waiting for confirmation"; watch.watch(function (err, hash) { diff --git a/libjsqrc/ethereumjs/example/event_inc.html b/libjsqrc/ethereumjs/example/event_inc.html index 16eaa046f..01671c475 100644 --- a/libjsqrc/ethereumjs/example/event_inc.html +++ b/libjsqrc/ethereumjs/example/event_inc.html @@ -18,29 +18,10 @@ " } " + " uint x; " + "}"; - var code = web3.eth.compile.solidity(source).code; - /*var code = "5b60456000600050819055505b608c8060196000396000f3006000357c010000000000000000000000000000000000000000000000000000000090048063371303c014602e57005b6034603a565b60006000f35b6000600081815054600101919050819055506001600260006000505406147f6e61ef44ac2747ff8b84d353a908eb8bd5c3fb118334d57698c5cfc7041196ad600060006000505481526020016000a25b56";*/ - var desc = [{ - "constant" : false, - "inputs" : [], - "name" : "inc", - "outputs" : [], - "type" : "function" - }, { - "anonymous" : false, - "inputs" : [{ - "indexed" : true, - "name" : "odd", - "type" : "bool" - }, { - "indexed" : false, - "name" : "x", - "type" : "uint256" - }], - "name" : "Incremented", - "type" : "event" - }]; + var compiled = web3.eth.compile.solidity(source); + var code = compiled.Contract.code; + var abi = compiled.Contract.info.abiDefinition; var address; var contract; @@ -55,7 +36,7 @@ var watch = web3.eth.filter('latest'); - contract = web3.eth.contract(desc).new({data: code}); + contract = web3.eth.contract(abi).new({data: code}); console.log('address: ' + contract.address); diff --git a/libjsqrc/ethereumjs/example/icap.html b/libjsqrc/ethereumjs/example/icap.html new file mode 100644 index 000000000..271cf6293 --- /dev/null +++ b/libjsqrc/ethereumjs/example/icap.html @@ -0,0 +1,203 @@ + + + + + + + + +

ICAP transfer

+
+

namereg address

+
+
+ eg. 0x436474facc88948696b371052a1befb801f003ca or 'default') +
+
+ + +
+ +
+

exchange identifier

+
+
+ eg. WYWY +
+
+ + +
+ +
+

client identifier

+
+
+ eg. GAVOFYORK +
+
+ + +
+ +
+

value

+
+
+ eg. 100 +
+
+ + +
+ +
 
+
+ IBAN: + + +
+
 
+
+ + +
+ +
+

transfers

+
+
+
    +
    + + diff --git a/libjsqrc/ethereumjs/example/namereg.html b/libjsqrc/ethereumjs/example/namereg.html new file mode 100644 index 000000000..c86f63277 --- /dev/null +++ b/libjsqrc/ethereumjs/example/namereg.html @@ -0,0 +1,102 @@ + + + + + + + + + This example shows only part of namereg functionalities. Namereg contract is available
    here + +

    Namereg

    +

    Search for name

    +
    + Address: + + Name: + +
    +

    Search for address

    +
    + Name: + + Address: + +
    +

    Register name

    +
    + Check if name is available: + + +
    +
    + +
    +

    + If you own the name, you can also change the address it points to +
    + Address: + + + Current address : + +
    + + + + diff --git a/libjsqrc/ethereumjs/example/natspec_contract.html b/libjsqrc/ethereumjs/example/natspec_contract.html deleted file mode 100644 index 2672ae19e..000000000 --- a/libjsqrc/ethereumjs/example/natspec_contract.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - -

    contract

    -
    -
    - -
    - -
    - - - 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/index.js b/libjsqrc/ethereumjs/index.js index 7a1c06902..ef2752dab 100644 --- a/libjsqrc/ethereumjs/index.js +++ b/libjsqrc/ethereumjs/index.js @@ -2,6 +2,8 @@ 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') { diff --git a/libjsqrc/ethereumjs/lib/solidity/param.js b/libjsqrc/ethereumjs/lib/solidity/param.js index 7c3254659..25fa3f4f8 100644 --- a/libjsqrc/ethereumjs/lib/solidity/param.js +++ b/libjsqrc/ethereumjs/lib/solidity/param.js @@ -72,7 +72,7 @@ SolidityParam.prototype.combine = function (param) { * @returns {Boolean} */ SolidityParam.prototype.isDynamic = function () { - return this.value.length > 64; + return this.value.length > 64 || this.offset !== undefined; }; /** @@ -188,7 +188,7 @@ SolidityParam.decodeBytes = function (bytes, index) { var offset = getOffset(bytes, index); // 2 * , cause we also parse length - return new SolidityParam(bytes.substr(offset * 2, 2 * 64)); + return new SolidityParam(bytes.substr(offset * 2, 2 * 64), 0); }; /** @@ -203,7 +203,7 @@ 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)); + return new SolidityParam(bytes.substr(offset * 2, (length + 1) * 64), 0); }; module.exports = SolidityParam; diff --git a/libjsqrc/ethereumjs/lib/utils/config.js b/libjsqrc/ethereumjs/lib/utils/config.js index b5365ccfd..d25b5d7ba 100644 --- a/libjsqrc/ethereumjs/lib/utils/config.js +++ b/libjsqrc/ethereumjs/lib/utils/config.js @@ -36,26 +36,34 @@ /// required to define ETH_BIGNUMBER_ROUNDING_MODE var BigNumber = require('bignumber.js'); -var ETH_UNITS = [ - 'wei', - 'Kwei', - 'Mwei', - 'Gwei', - 'szabo', - 'finney', - 'ether', - 'grand', - 'Mether', - 'Gether', - 'Tether', - 'Pether', - 'Eether', - 'Zether', - 'Yether', - 'Nether', - 'Dether', - 'Vether', - 'Uether' +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 = { diff --git a/libjsqrc/ethereumjs/lib/utils/sha3.js b/libjsqrc/ethereumjs/lib/utils/sha3.js new file mode 100644 index 000000000..dce1d954b --- /dev/null +++ b/libjsqrc/ethereumjs/lib/utils/sha3.js @@ -0,0 +1,39 @@ +/* + 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(); +}; + diff --git a/libjsqrc/ethereumjs/lib/utils/utils.js b/libjsqrc/ethereumjs/lib/utils/utils.js index 91964c333..42363ab88 100644 --- a/libjsqrc/ethereumjs/lib/utils/utils.js +++ b/libjsqrc/ethereumjs/lib/utils/utils.js @@ -36,22 +36,30 @@ var BigNumber = require('bignumber.js'); var unitMap = { - 'wei': '1', - 'kwei': '1000', - 'ada': '1000', - 'mwei': '1000000', - 'babbage': '1000000', - 'gwei': '1000000000', - 'shannon': '1000000000', - 'szabo': '1000000000000', - 'finney': '1000000000000000', - 'ether': '1000000000000000000', - 'kether': '1000000000000000000000', - 'grand': '1000000000000000000000', - 'einstein': '1000000000000000000000', - 'mether': '1000000000000000000000000', - 'gether': '1000000000000000000000000000', - 'tether': '1000000000000000000000000000000' + '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' }; /** @@ -239,13 +247,14 @@ var getValueOfUnit = function (unit) { * Takes a number of wei and converts it to any other ether unit. * * Possible units are: - * - kwei/ada - * - mwei/babbage - * - gwei/shannon - * - szabo - * - finney - * - ether - * - kether/grand/einstein + * 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 @@ -265,13 +274,14 @@ var fromWei = function(number, unit) { * Takes a number of a unit and converts it to wei. * * Possible units are: - * - kwei/ada - * - mwei/babbage - * - gwei/shannon - * - szabo - * - finney - * - ether - * - kether/grand/einstein + * 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 @@ -447,6 +457,18 @@ var isJson = function (str) { } }; +/** + * 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, @@ -470,6 +492,7 @@ module.exports = { isObject: isObject, isBoolean: isBoolean, isArray: isArray, - isJson: isJson + isJson: isJson, + isIBAN: isIBAN }; diff --git a/libjsqrc/ethereumjs/lib/version.json b/libjsqrc/ethereumjs/lib/version.json index 70753fc9d..8fd887d4d 100644 --- a/libjsqrc/ethereumjs/lib/version.json +++ b/libjsqrc/ethereumjs/lib/version.json @@ -1,3 +1,3 @@ { - "version": "0.4.2" + "version": "0.5.0" } diff --git a/libjsqrc/ethereumjs/lib/web3.js b/libjsqrc/ethereumjs/lib/web3.js index 98460fea4..394ae450b 100644 --- a/libjsqrc/ethereumjs/lib/web3.js +++ b/libjsqrc/ethereumjs/lib/web3.js @@ -34,18 +34,11 @@ 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 Method = require('./web3/method'); +var c = require('./utils/config'); var Property = require('./web3/property'); var Batch = require('./web3/batch'); - -var web3Methods = [ - new Method({ - name: 'sha3', - call: 'web3_sha3', - params: 1 - }) -]; +var sha3 = require('./utils/sha3'); var web3Properties = [ new Property({ @@ -130,6 +123,8 @@ 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(); }; @@ -156,7 +151,6 @@ Object.defineProperty(web3.eth, 'defaultAccount', { }); /// setups all api methods -setupMethods(web3, web3Methods); setupProperties(web3, web3Properties); setupMethods(web3.net, net.methods); setupProperties(web3.net, net.properties); @@ -165,5 +159,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 Property({ + name: 'blockQueueStatus', + call: 'admin_eth_blockQueueStatus', + params: 1, + inputFormatter: [function() { return web3.admin.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/libjsqrc/ethereumjs/lib/web3/event.js b/libjsqrc/ethereumjs/lib/web3/event.js index f9305f8b8..7295cf63d 100644 --- a/libjsqrc/ethereumjs/lib/web3/event.js +++ b/libjsqrc/ethereumjs/lib/web3/event.js @@ -24,6 +24,7 @@ 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 @@ -77,7 +78,7 @@ SolidityEvent.prototype.typeName = function () { * @return {String} event signature */ SolidityEvent.prototype.signature = function () { - return web3.sha3(web3.fromAscii(this._name)).slice(2); + return sha3(this._name); }; /** diff --git a/libjsqrc/ethereumjs/lib/web3/function.js b/libjsqrc/ethereumjs/lib/web3/function.js index e9ad5d03a..1b377be84 100644 --- a/libjsqrc/ethereumjs/lib/web3/function.js +++ b/libjsqrc/ethereumjs/lib/web3/function.js @@ -23,6 +23,7 @@ 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 @@ -69,12 +70,12 @@ SolidityFunction.prototype.toPayload = function (args) { * @return {String} function signature */ SolidityFunction.prototype.signature = function () { - return web3.sha3(web3.fromAscii(this._name)).slice(2, 10); + return sha3(this._name).slice(0, 8); }; SolidityFunction.prototype.unpackOutput = function (output) { - if (output === null) { + if (!output) { return; } @@ -94,7 +95,7 @@ SolidityFunction.prototype.unpackOutput = function (output) { * @return {String} output bytes */ SolidityFunction.prototype.call = function () { - var args = Array.prototype.slice.call(arguments); + var args = Array.prototype.slice.call(arguments).filter(function (a) {return a !== undefined; }); var callback = this.extractCallback(args); var payload = this.toPayload(args); @@ -116,18 +117,35 @@ SolidityFunction.prototype.call = function () { * @param {Object} options */ SolidityFunction.prototype.sendTransaction = function () { - var args = Array.prototype.slice.call(arguments); + 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) { - web3.eth.sendTransaction(payload); - return; + 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 * @@ -195,6 +213,7 @@ SolidityFunction.prototype.attachToContract = function (contract) { 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; diff --git a/libjsqrc/ethereumjs/lib/web3/icap.js b/libjsqrc/ethereumjs/lib/web3/icap.js new file mode 100644 index 000000000..aaff290fc --- /dev/null +++ b/libjsqrc/ethereumjs/lib/web3/icap.js @@ -0,0 +1,108 @@ +/* + 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; + diff --git a/libjsqrc/ethereumjs/lib/web3/namereg.js b/libjsqrc/ethereumjs/lib/web3/namereg.js new file mode 100644 index 000000000..46ee0e1d1 --- /dev/null +++ b/libjsqrc/ethereumjs/lib/web3/namereg.js @@ -0,0 +1,46 @@ +/* + 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); + 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/libjsqrc/ethereumjs/lib/web3/transfer.js b/libjsqrc/ethereumjs/lib/web3/transfer.js new file mode 100644 index 000000000..615988943 --- /dev/null +++ b/libjsqrc/ethereumjs/lib/web3/transfer.js @@ -0,0 +1,94 @@ +/* + 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; + diff --git a/libjsqrc/ethereumjs/package.js b/libjsqrc/ethereumjs/package.js index 953edb4fb..ccf7ddd75 100644 --- a/libjsqrc/ethereumjs/package.js +++ b/libjsqrc/ethereumjs/package.js @@ -1,7 +1,7 @@ /* jshint ignore:start */ Package.describe({ name: 'ethereum:web3', - version: '0.4.2', + version: '0.5.0', summary: 'Ethereum JavaScript API, middleware to talk to a ethreum node over RPC', git: 'https://github.com/ethereum/ethereum.js', // By default, Meteor will default to using README.md for documentation. diff --git a/libjsqrc/ethereumjs/package.json b/libjsqrc/ethereumjs/package.json index 59d4f6211..3ff3028bb 100644 --- a/libjsqrc/ethereumjs/package.json +++ b/libjsqrc/ethereumjs/package.json @@ -1,7 +1,7 @@ { "name": "web3", "namespace": "ethereum", - "version": "0.4.2", + "version": "0.5.0", "description": "Ethereum JavaScript API, middleware to talk to a ethereum node over RPC", "main": "./index.js", "directories": { @@ -9,6 +9,7 @@ }, "dependencies": { "bignumber.js": "debris/bignumber.js#master", + "crypto-js": "^3.1.4", "xmlhttprequest": "*" }, "browser": { diff --git a/libjsqrc/ethereumjs/test/batch.js b/libjsqrc/ethereumjs/test/batch.js index 69ae8fd58..f368a5d74 100644 --- a/libjsqrc/ethereumjs/test/batch.js +++ b/libjsqrc/ethereumjs/test/batch.js @@ -58,10 +58,6 @@ describe('lib/web3/batch', function () { var address = '0x0000000000000000000000000000000000000000'; var result = '0x126'; var result2 = '0x0000000000000000000000000000000000000000000000000000000000000123'; - var signature = '0x001122334455'; - - // TODO: fix this, maybe in browser sha3? - provider.injectResult(signature); var counter = 0; var callback = function (err, r) { diff --git a/libjsqrc/ethereumjs/test/coder.decodeParam.js b/libjsqrc/ethereumjs/test/coder.decodeParam.js index 23b0228eb..959e96cf2 100644 --- a/libjsqrc/ethereumjs/test/coder.decodeParam.js +++ b/libjsqrc/ethereumjs/test/coder.decodeParam.js @@ -24,6 +24,8 @@ describe('lib/solidity/coder', function () { test({ type: 'bytes', expected: 'gavofyork', value: '0000000000000000000000000000000000000000000000000000000000000020' + '0000000000000000000000000000000000000000000000000000000000000009' + '6761766f66796f726b0000000000000000000000000000000000000000000000'}); + test({ type: 'int[]', expected: [], value: '0000000000000000000000000000000000000000000000000000000000000020' + + '0000000000000000000000000000000000000000000000000000000000000000'}); test({ type: 'int[]', expected: [new bn(3)], value: '0000000000000000000000000000000000000000000000000000000000000020' + '0000000000000000000000000000000000000000000000000000000000000001' + '0000000000000000000000000000000000000000000000000000000000000003'}); diff --git a/libjsqrc/ethereumjs/test/coder.encodeParam.js b/libjsqrc/ethereumjs/test/coder.encodeParam.js index 60d1c618e..55ff657c2 100644 --- a/libjsqrc/ethereumjs/test/coder.encodeParam.js +++ b/libjsqrc/ethereumjs/test/coder.encodeParam.js @@ -24,6 +24,8 @@ describe('lib/solidity/coder', function () { test({ type: 'bytes', value: 'gavofyork', expected: '0000000000000000000000000000000000000000000000000000000000000020' + '0000000000000000000000000000000000000000000000000000000000000009' + '6761766f66796f726b0000000000000000000000000000000000000000000000'}); + test({ type: 'int[]', value: [], expected: '0000000000000000000000000000000000000000000000000000000000000020' + + '0000000000000000000000000000000000000000000000000000000000000000'}); test({ type: 'int[]', value: [3], expected: '0000000000000000000000000000000000000000000000000000000000000020' + '0000000000000000000000000000000000000000000000000000000000000001' + '0000000000000000000000000000000000000000000000000000000000000003'}); diff --git a/libjsqrc/ethereumjs/test/contract.js b/libjsqrc/ethereumjs/test/contract.js index a46a8cab3..00f9cbcc8 100644 --- a/libjsqrc/ethereumjs/test/contract.js +++ b/libjsqrc/ethereumjs/test/contract.js @@ -5,6 +5,7 @@ var FakeHttpProvider = require('./helpers/FakeHttpProvider'); var FakeHttpProvider2 = require('./helpers/FakeHttpProvider2'); var utils = require('../lib/utils/utils'); var BigNumber = require('bignumber.js'); +var sha3 = require('../lib/utils/sha3'); var desc = [{ "name": "balance(address)", @@ -60,34 +61,28 @@ describe('web3.eth.contract', function () { var provider = new FakeHttpProvider(); web3.setProvider(provider); web3.reset(); // reset different polls - var sha3 = '0x5131231231231231231231'; - provider.injectResult(sha3); + var signature = 'Changed(address,uint256,uint256,uint256)'; var step = 0; provider.injectValidation(function (payload) { if (step === 0) { step = 1; - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'web3_sha3'); - assert.equal(payload.params[0], web3.fromAscii('Changed(address,uint256,uint256,uint256)')); - } else if (step === 1) { - step = 2; provider.injectResult(3); assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_newFilter'); assert.deepEqual(payload.params[0], { topics: [ - sha3, + '0x' + sha3(signature), '0x0000000000000000000000001234567890123456789012345678901234567890', null ], address: '0x1234567890123456789012345678901234567890' }); - } else if (step === 2) { - step = 3; + } else if (step === 1) { + step = 2; provider.injectResult([{ address: address, topics: [ - sha3, + '0x' + sha3(signature), '0x0000000000000000000000001234567890123456789012345678901234567890', '0x0000000000000000000000000000000000000000000000000000000000000001' ], @@ -97,11 +92,11 @@ describe('web3.eth.contract', function () { }]); assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_getFilterLogs'); - } else if (step === 3 && utils.isArray(payload)) { + } else if (step === 2 && utils.isArray(payload)) { provider.injectBatchResults([[{ address: address, topics: [ - sha3, + '0x' + sha3(signature), '0x0000000000000000000000001234567890123456789012345678901234567890', '0x0000000000000000000000000000000000000000000000000000000000000001' ], @@ -135,53 +130,37 @@ describe('web3.eth.contract', function () { var provider = new FakeHttpProvider(); web3.setProvider(provider); web3.reset(); - var sha3 = '0x5131231231231231231231'; + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032'); + var signature = 'balance(address)' var address = '0x1234567890123456789012345678901234567890'; - provider.injectResult(sha3); - var step = 0; provider.injectValidation(function (payload) { - if (step === 0) { - step = 1; - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'web3_sha3'); - assert.equal(payload.params[0], web3.fromAscii('balance(address)')); - } else if (step === 1) { - assert.equal(payload.method, 'eth_call'); - assert.deepEqual(payload.params, [{ - data: sha3.slice(0, 10) + '0000000000000000000000001234567890123456789012345678901234567890', - to: address - }, 'latest']); - } + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: '0x' + sha3(signature).slice(0, 8) + '0000000000000000000000001234567890123456789012345678901234567890', + to: address + }, 'latest']); }); var contract = web3.eth.contract(desc).at(address); - contract.balance(address); + var r = contract.balance(address); + assert.deepEqual(new BigNumber(0x32), r); }); it('should sendTransaction to contract function', function () { var provider = new FakeHttpProvider(); web3.setProvider(provider); web3.reset(); - var sha3 = '0x5131231231231231231231'; + var signature = 'send(address,uint256)'; var address = '0x1234567890123456789012345678901234567890'; - provider.injectResult(sha3); - var step = 0; provider.injectValidation(function (payload) { - if (step === 0) { - step = 1; - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'web3_sha3'); - assert.equal(payload.params[0], web3.fromAscii('send(address,uint256)')); - } else if (step === 1) { - assert.equal(payload.method, 'eth_sendTransaction'); - assert.deepEqual(payload.params, [{ - data: sha3.slice(0, 10) + - '0000000000000000000000001234567890123456789012345678901234567890' + - '0000000000000000000000000000000000000000000000000000000000000011' , - to: address - }]); - } + assert.equal(payload.method, 'eth_sendTransaction'); + assert.deepEqual(payload.params, [{ + data: '0x' + sha3(signature).slice(0, 8) + + '0000000000000000000000001234567890123456789012345678901234567890' + + '0000000000000000000000000000000000000000000000000000000000000011' , + to: address + }]); }); var contract = web3.eth.contract(desc).at(address); @@ -194,30 +173,23 @@ describe('web3.eth.contract', function () { var provider = new FakeHttpProvider(); web3.setProvider(provider); web3.reset(); - var sha3 = '0x5131231231231231231231'; + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032'); + var signature = 'balance(address)'; var address = '0x1234567890123456789012345678901234567890'; - provider.injectResult(sha3); - var step = 0; provider.injectValidation(function (payload) { - if (step === 0) { - step = 1; - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'web3_sha3'); - assert.equal(payload.params[0], web3.fromAscii('balance(address)')); - } else if (step === 1) { - assert.equal(payload.method, 'eth_call'); - assert.deepEqual(payload.params, [{ - data: sha3.slice(0, 10) + '0000000000000000000000001234567890123456789012345678901234567890', - to: address, - from: address, - gas: '0xc350' - }, 'latest']); - } + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: '0x' + sha3(signature).slice(0, 8) + '0000000000000000000000001234567890123456789012345678901234567890', + to: address, + from: address, + gas: '0xc350' + }, 'latest']); }); var contract = web3.eth.contract(desc).at(address); - contract.balance(address, {from: address, gas: 50000}); + var r = contract.balance(address, {from: address, gas: 50000}); + assert.deepEqual(new BigNumber(0x32), r); }); @@ -226,30 +198,23 @@ describe('web3.eth.contract', function () { var provider = new FakeHttpProvider(); web3.setProvider(provider); web3.reset(); - var sha3 = '0x5131231231231231231231'; + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032'); + var signature = 'balance(address)'; var address = '0x1234567890123456789012345678901234567890'; - provider.injectResult(sha3); - var step = 0; provider.injectValidation(function (payload) { - if (step === 0) { - step = 1; - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'web3_sha3'); - assert.equal(payload.params[0], web3.fromAscii('balance(address)')); - } else if (step === 1) { - assert.equal(payload.method, 'eth_call'); - assert.deepEqual(payload.params, [{ - data: sha3.slice(0, 10) + '0000000000000000000000001234567890123456789012345678901234567890', - to: address, - from: address, - gas: '0xc350' - }, 'latest']); - } + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: '0x' + sha3(signature).slice(0, 8) + '0000000000000000000000001234567890123456789012345678901234567890', + to: address, + from: address, + gas: '0xc350' + }, 'latest']); }); var contract = web3.eth.contract(desc).at(address); - contract.balance.call(address, {from: address, gas: 50000}); + var r = contract.balance.call(address, {from: address, gas: 50000}); + assert.deepEqual(new BigNumber(0x32), r); }); @@ -257,29 +222,20 @@ describe('web3.eth.contract', function () { var provider = new FakeHttpProvider(); web3.setProvider(provider); web3.reset(); - var sha3 = '0x5131231231231231231231'; + var signature = 'send(address,uint256)'; var address = '0x1234567890123456789012345678901234567890'; - provider.injectResult(sha3); - var step = 0; provider.injectValidation(function (payload) { - if (step === 0) { - step = 1; - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'web3_sha3'); - assert.equal(payload.params[0], web3.fromAscii('send(address,uint256)')); - } else if (step === 1) { - assert.equal(payload.method, 'eth_sendTransaction'); - assert.deepEqual(payload.params, [{ - data: sha3.slice(0, 10) + - '0000000000000000000000001234567890123456789012345678901234567890' + - '0000000000000000000000000000000000000000000000000000000000000011' , - to: address, - from: address, - gas: '0xc350', - gasPrice: '0xbb8', - value: '0x2710' - }]); - } + assert.equal(payload.method, 'eth_sendTransaction'); + assert.deepEqual(payload.params, [{ + data: '0x' + sha3(signature).slice(0, 8) + + '0000000000000000000000001234567890123456789012345678901234567890' + + '0000000000000000000000000000000000000000000000000000000000000011' , + to: address, + from: address, + gas: '0xc350', + gasPrice: '0xbb8', + value: '0x2710' + }]); }); var contract = web3.eth.contract(desc).at(address); @@ -291,29 +247,20 @@ describe('web3.eth.contract', function () { var provider = new FakeHttpProvider(); web3.setProvider(provider); web3.reset(); - var sha3 = '0x5131231231231231231231'; + var signature = 'send(address,uint256)'; var address = '0x1234567890123456789012345678901234567890'; - provider.injectResult(sha3); - var step = 0; provider.injectValidation(function (payload) { - if (step === 0) { - step = 1; - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'web3_sha3'); - assert.equal(payload.params[0], web3.fromAscii('send(address,uint256)')); - } else if (step === 1) { - assert.equal(payload.method, 'eth_sendTransaction'); - assert.deepEqual(payload.params, [{ - data: sha3.slice(0, 10) + - '0000000000000000000000001234567890123456789012345678901234567890' + - '0000000000000000000000000000000000000000000000000000000000000011' , - to: address, - from: address, - gas: '0xc350', - gasPrice: '0xbb8', - value: '0x2710' - }]); - } + assert.equal(payload.method, 'eth_sendTransaction'); + assert.deepEqual(payload.params, [{ + data: '0x' + sha3(signature).slice(0, 8) + + '0000000000000000000000001234567890123456789012345678901234567890' + + '0000000000000000000000000000000000000000000000000000000000000011' , + to: address, + from: address, + gas: '0xc350', + gasPrice: '0xbb8', + value: '0x2710' + }]); }); var contract = web3.eth.contract(desc).at(address); @@ -325,29 +272,20 @@ describe('web3.eth.contract', function () { var provider = new FakeHttpProvider(); web3.setProvider(provider); web3.reset(); - var sha3 = '0x5131231231231231231231'; var address = '0x1234567890123456789012345678901234567890'; - provider.injectResult(sha3); - var step = 0; + var signature = 'send(address,uint256)'; provider.injectValidation(function (payload) { - if (step === 0) { - step = 1; - assert.equal(payload.jsonrpc, '2.0'); - assert.equal(payload.method, 'web3_sha3'); - assert.equal(payload.params[0], web3.fromAscii('send(address,uint256)')); - } else if (step === 1) { - assert.equal(payload.method, 'eth_sendTransaction'); - assert.deepEqual(payload.params, [{ - data: sha3.slice(0, 10) + - '0000000000000000000000001234567890123456789012345678901234567890' + - '0000000000000000000000000000000000000000000000000000000000000011' , - to: address, - from: address, - gas: '0xc350', - gasPrice: '0xbb8', - value: '0x2710' - }]); - } + assert.equal(payload.method, 'eth_sendTransaction'); + assert.deepEqual(payload.params, [{ + data: '0x' + sha3(signature).slice(0, 8) + + '0000000000000000000000001234567890123456789012345678901234567890' + + '0000000000000000000000000000000000000000000000000000000000000011' , + to: address, + from: address, + gas: '0xc350', + gasPrice: '0xbb8', + value: '0x2710' + }]); }); var contract = web3.eth.contract(desc).at(address); @@ -358,32 +296,52 @@ describe('web3.eth.contract', function () { }); }); + it('should explicitly estimateGas with optional params', function () { + var provider = new FakeHttpProvider(); + web3.setProvider(provider); + web3.reset(); + var signature = 'send(address,uint256)'; + var address = '0x1234567890123456789012345678901234567890'; + provider.injectValidation(function (payload) { + assert.equal(payload.method, 'eth_estimateGas'); + assert.deepEqual(payload.params, [{ + data: '0x' + sha3(signature).slice(0, 8) + + '0000000000000000000000001234567890123456789012345678901234567890' + + '0000000000000000000000000000000000000000000000000000000000000011' , + to: address, + from: address, + gas: '0xc350', + gasPrice: '0xbb8', + value: '0x2710' + }]); + }); + + var contract = web3.eth.contract(desc).at(address); + + contract.send.estimateGas(address, 17, {from: address, gas: 50000, gasPrice: 3000, value: 10000}); + }); + it('should call testArr method and properly parse result', function () { var provider = new FakeHttpProvider2(); web3.setProvider(provider); web3.reset(); - var sha3 = '0x5131231231231231231231'; + var signature = 'testArr(int[])'; var address = '0x1234567890123456789012345678901234567890'; provider.injectResultList([{ - result: sha3 - }, { result: '0x0000000000000000000000000000000000000000000000000000000000000005' }]); - var step = 0; + provider.injectValidation(function (payload) { - if (step === 1) { // getting sha3 is first - assert.equal(payload.method, 'eth_call'); - assert.deepEqual(payload.params, [{ - data: sha3.slice(0, 10) + - '0000000000000000000000000000000000000000000000000000000000000020' + - '0000000000000000000000000000000000000000000000000000000000000001' + - '0000000000000000000000000000000000000000000000000000000000000003', - to: address - }, - 'latest' + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: '0x' + sha3(signature).slice(0, 8) + + '0000000000000000000000000000000000000000000000000000000000000020' + + '0000000000000000000000000000000000000000000000000000000000000001' + + '0000000000000000000000000000000000000000000000000000000000000003', + to: address + }, + 'latest' ]); - } - step++; }); var contract = web3.eth.contract(desc).at(address); @@ -396,28 +354,22 @@ describe('web3.eth.contract', function () { var provider = new FakeHttpProvider2(); web3.setProvider(provider); web3.reset(); - var sha3 = '0x5131231231231231231231'; + var signature = 'testArr(int[])'; var address = '0x1234567890123456789012345678901234567890'; provider.injectResultList([{ - result: sha3 - }, { result: '0x0000000000000000000000000000000000000000000000000000000000000005' }]); - var step = 0; provider.injectValidation(function (payload) { - if (step === 1) { // getting sha3 is first - assert.equal(payload.method, 'eth_call'); - assert.deepEqual(payload.params, [{ - data: sha3.slice(0, 10) + - '0000000000000000000000000000000000000000000000000000000000000020' + - '0000000000000000000000000000000000000000000000000000000000000001' + - '0000000000000000000000000000000000000000000000000000000000000003', - to: address - }, - 'latest' - ]); - } - step++; + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: '0x' + sha3(signature).slice(0, 8) + + '0000000000000000000000000000000000000000000000000000000000000020' + + '0000000000000000000000000000000000000000000000000000000000000001' + + '0000000000000000000000000000000000000000000000000000000000000003', + to: address + }, + 'latest' + ]); }); var contract = web3.eth.contract(desc).at(address); diff --git a/libjsqrc/ethereumjs/test/sha3.js b/libjsqrc/ethereumjs/test/sha3.js new file mode 100644 index 000000000..e349887e7 --- /dev/null +++ b/libjsqrc/ethereumjs/test/sha3.js @@ -0,0 +1,17 @@ +var chai = require('chai'); +var assert = chai.assert; +var sha3 = require('../lib/utils/sha3'); +var web3 = require('../index'); + +describe('lib/utils/sha3', function () { + var test = function (v, e) { + it('should encode ' + v + ' to ' + e, function () { + assert.equal(sha3(v), e); + }); + }; + + test('test123', 'f81b517a242b218999ec8eec0ea6e2ddbef2a367a14e93f4a32a39e260f686ad'); + test('test(int)', 'f4d03772bec1e62fbe8c5691e1a9101e520e8f8b5ca612123694632bf3cb51b1'); + test(web3.fromAscii('test123'), 'f81b517a242b218999ec8eec0ea6e2ddbef2a367a14e93f4a32a39e260f686ad'); +}); + diff --git a/libjsqrc/ethereumjs/test/utils.isIBAN.js b/libjsqrc/ethereumjs/test/utils.isIBAN.js new file mode 100644 index 000000000..194ccaa23 --- /dev/null +++ b/libjsqrc/ethereumjs/test/utils.isIBAN.js @@ -0,0 +1,32 @@ +var chai = require('chai'); +var utils = require('../lib/utils/utils.js'); +var assert = chai.assert; + +var tests = [ + { obj: function () {}, is: false}, + { obj: new Function(), is: false}, + { obj: 'function', is: false}, + { obj: {}, is: false}, + { obj: '[]', is: false}, + { obj: '[1, 2]', is: false}, + { obj: '{}', is: false}, + { obj: '{"a": 123, "b" :3,}', is: false}, + { obj: '{"c" : 2}', is: false}, + { obj: 'XE81ETHXREGGAVOFYORK', is: true}, + { obj: 'XE81ETCXREGGAVOFYORK', is: false}, + { obj: 'XE81ETHXREGGAVOFYORKD', is: false}, + { obj: 'XE81ETHXREGGaVOFYORK', is: false}, + { obj: 'XE7338O073KYGTWWZN0F2WZ0R8PX5ZPPZS', is: true}, + { obj: 'XD7338O073KYGTWWZN0F2WZ0R8PX5ZPPZS', is: false} +]; + +describe('lib/utils/utils', function () { + describe('isIBAN', function () { + tests.forEach(function (test) { + it('shoud test if value ' + test.obj + ' is iban: ' + test.is, function () { + assert.equal(utils.isIBAN(test.obj), test.is); + }); + }); + }); +}); + diff --git a/libjsqrc/ethereumjs/test/utils.toWei.js b/libjsqrc/ethereumjs/test/utils.toWei.js index 3bb0997c6..55b6c9328 100644 --- a/libjsqrc/ethereumjs/test/utils.toWei.js +++ b/libjsqrc/ethereumjs/test/utils.toWei.js @@ -19,6 +19,14 @@ describe('lib/utils/utils', function () { assert.equal(utils.toWei(1, 'gether'), '1000000000000000000000000000'); assert.equal(utils.toWei(1, 'tether'), '1000000000000000000000000000000'); + assert.equal(utils.toWei(1, 'kwei'), utils.toWei(1, 'femtoether')); + assert.equal(utils.toWei(1, 'babbage'), utils.toWei(1, 'picoether')); + assert.equal(utils.toWei(1, 'shannon'), utils.toWei(1, 'nanoether')); + assert.equal(utils.toWei(1, 'szabo'), utils.toWei(1, 'microether')); + assert.equal(utils.toWei(1, 'finney'), utils.toWei(1, 'milliether')); + assert.equal(utils.toWei(1, 'milli'), utils.toWei(1, 'milliether')); + assert.equal(utils.toWei(1, 'milli'), utils.toWei(1000, 'micro')); + assert.throws(function () {utils.toWei(1, 'wei1');}, Error); }); }); diff --git a/libjsqrc/ethereumjs/test/web3.eth.sendIBANTransaction.js b/libjsqrc/ethereumjs/test/web3.eth.sendIBANTransaction.js new file mode 100644 index 000000000..9d478e13f --- /dev/null +++ b/libjsqrc/ethereumjs/test/web3.eth.sendIBANTransaction.js @@ -0,0 +1,49 @@ +var chai = require('chai'); +var assert = chai.assert; +var web3 = require('../index'); +var FakeHttpProvider = require('./helpers/FakeHttpProvider'); +var FakeHttpProvider2 = require('./helpers/FakeHttpProvider2'); + +describe('web3.eth.sendIBANTransaction', function () { + it('should send transaction', function () { + + var iban = 'XE81ETHXREGGAVOFYORK'; + var address = '0x1234567890123456789012345678901234500000'; + var exAddress = '0x1234567890123456789012345678901234567890' + + var provider = new FakeHttpProvider2(); + web3.setProvider(provider); + web3.reset(); + + provider.injectResultList([{ + result: exAddress + }, { + result: '' + }]); + + var step = 0; + provider.injectValidation(function (payload) { + if (step === 0) { + step++; + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: '0x3b3b57de5852454700000000000000000000000000000000000000000000000000000000', + to: web3.eth.namereg.address + }, "latest"]); + + return; + } + assert.equal(payload.method, 'eth_sendTransaction'); + assert.deepEqual(payload.params, [{ + data: '0xb214faa54741564f46594f524b0000000000000000000000000000000000000000000000', + from: address, + to: exAddress, + value: payload.params[0].value // don't check this + }]); + }); + + web3.eth.sendIBANTransaction(address, iban, 10000); + + }); +}); + diff --git a/libjsqrc/ethereumjs/test/web3.sha3.js b/libjsqrc/ethereumjs/test/web3.sha3.js deleted file mode 100644 index 0ae104962..000000000 --- a/libjsqrc/ethereumjs/test/web3.sha3.js +++ /dev/null @@ -1,16 +0,0 @@ -var BigNumber = require('bignumber.js'); -var web3 = require('../index'); -var testMethod = require('./helpers/test.method.js'); - -var method = 'sha3'; - -var tests = [{ - args: ['myString'], - formattedArgs: ['myString'], - result: '0x319319f831983198319881', - formattedResult: '0x319319f831983198319881', - call: 'web3_'+ method -}]; - -testMethod.runTests(null, method, tests); - diff --git a/libp2p/Capability.cpp b/libp2p/Capability.cpp index ecc458730..bc4aa0b04 100644 --- a/libp2p/Capability.cpp +++ b/libp2p/Capability.cpp @@ -23,18 +23,19 @@ #include #include "Session.h" +#include "Host.h" using namespace std; using namespace dev; using namespace dev::p2p; -Capability::Capability(Session* _s, HostCapabilityFace* _h, unsigned _idOffset): m_session(_s), m_host(_h), m_idOffset(_idOffset) +Capability::Capability(Session* _s, HostCapabilityFace* _h, unsigned _idOffset): m_session(_s), m_hostCap(_h), m_idOffset(_idOffset) { - clog(NetConnect) << "New session for capability" << m_host->name() << "; idOffset:" << m_idOffset; + clog(NetConnect) << "New session for capability" << m_hostCap->name() << "; idOffset:" << m_idOffset; } void Capability::disable(std::string const& _problem) { - clog(NetWarn) << "DISABLE: Disabling capability '" << m_host->name() << "'. Reason:" << _problem; + clog(NetWarn) << "DISABLE: Disabling capability '" << m_hostCap->name() << "'. Reason:" << _problem; m_enabled = false; } @@ -52,3 +53,8 @@ void Capability::addRating(int _r) { m_session->addRating(_r); } + +ReputationManager& Capability::repMan() const +{ + return host()->repMan(); +} diff --git a/libp2p/Capability.h b/libp2p/Capability.h index d09391655..b4f59b243 100644 --- a/libp2p/Capability.h +++ b/libp2p/Capability.h @@ -29,6 +29,8 @@ namespace dev namespace p2p { +class ReputationManager; + class Capability { friend class Session; @@ -43,7 +45,9 @@ public: static unsigned messageCount() { return 0; } */ Session* session() const { return m_session; } - HostCapabilityFace* hostCapability() const { return m_host; } + HostCapabilityFace* hostCapability() const { return m_hostCap; } + Host* host() const { return m_hostCap->host(); } + ReputationManager& repMan() const; protected: virtual bool interpret(unsigned _id, RLP const&) = 0; @@ -56,7 +60,7 @@ protected: private: Session* m_session; - HostCapabilityFace* m_host; + HostCapabilityFace* m_hostCap; bool m_enabled = true; unsigned m_idOffset; }; diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index c5e209d70..55389ed1b 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -55,6 +55,30 @@ void HostNodeTableHandler::processEvent(NodeId const& _n, NodeTableEventType con m_host.onNodeTableEvent(_n, _e); } +ReputationManager::ReputationManager() +{ +} + +void ReputationManager::noteRude(Session const& _s, std::string const& _sub) +{ + 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 +{ + 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): Worker("p2p", 0), m_restoreNetwork(_restoreNetwork.toBytes()), diff --git a/libp2p/Host.h b/libp2p/Host.h index 95b77d5c9..e9cae509c 100644 --- a/libp2p/Host.h +++ b/libp2p/Host.h @@ -46,6 +46,18 @@ namespace ba = boost::asio; namespace bi = ba::ip; +namespace std +{ +template<> struct hash> +{ + size_t operator()(pair const& _value) const + { + size_t ret = hash()(_value.first); + return ret ^ (hash()(_value.second) + 0x9e3779b9 + (ret << 6) + (ret >> 2)); + } +}; +} + namespace dev { @@ -67,6 +79,30 @@ private: Host& m_host; }; +struct SubReputation +{ + bool isRude = false; + int utility = 0; +}; + +struct Reputation +{ + std::unordered_map subs; +}; + +class ReputationManager +{ +public: + ReputationManager(); + + void noteRude(Session const& _s, std::string const& _sub = std::string()); + bool isRude(Session const& _s, std::string const& _sub = std::string()) const; + +private: + std::unordered_map, Reputation> m_nodes; ///< Nodes that were impolite while syncing. We avoid syncing from these if possible. + SharedMutex mutable x_nodes; +}; + /** * @brief The Host class * Capabilities should be registered prior to startNetwork, since m_capabilities is not thread-safe. @@ -153,6 +189,9 @@ public: /// @returns if network has been started. bool isStarted() const { return isWorking(); } + /// @returns our reputation manager. + ReputationManager& repMan() { return m_repMan; } + /// @returns if network is started and interactive. bool haveNetwork() const { return m_run && !!m_nodeTable; } @@ -256,6 +295,8 @@ private: std::chrono::steady_clock::time_point m_lastPing; ///< Time we sent the last ping to all peers. bool m_accepting = false; bool m_dropPeers = false; + + ReputationManager m_repMan; }; } diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index 260ce10ac..c3f0f2e35 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -72,6 +72,11 @@ Session::~Session() delete m_io; } +ReputationManager& Session::repMan() const +{ + return m_server->repMan(); +} + NodeId Session::id() const { return m_peer ? m_peer->id : NodeId(); @@ -453,6 +458,7 @@ void Session::doRead() else if (ec && length < tlen) { clog(NetWarn) << "Error reading - Abrupt peer disconnect: " << ec.message(); + repMan().noteRude(*this); drop(TCPError); return; } diff --git a/libp2p/Session.h b/libp2p/Session.h index 08006f890..6b45fe381 100644 --- a/libp2p/Session.h +++ b/libp2p/Session.h @@ -44,6 +44,7 @@ namespace p2p { class Peer; +class ReputationManager; /** * @brief The Session class @@ -76,6 +77,7 @@ public: static RLPStream& prep(RLPStream& _s, PacketType _t, unsigned _args = 0); void sealAndSend(RLPStream& _s); + ReputationManager& repMan() const; int rating() const; void addRating(int _r); diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index acb7b50c5..5be23b7c8 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -469,9 +469,6 @@ void FunctionDefinition::checkTypeRequirements() { if (!var->getType()->canLiveOutsideStorage()) BOOST_THROW_EXCEPTION(var->createTypeError("Type is required to live outside storage.")); - // todo delete when will be implemented arrays as parameter type in internal functions - if (getVisibility() == Visibility::Public && var->getType()->getCategory() == Type::Category::Array) - BOOST_THROW_EXCEPTION(var->createTypeError("Arrays only implemented for external functions.")); if (getVisibility() >= Visibility::Public && !(var->getType()->externalType())) BOOST_THROW_EXCEPTION(var->createTypeError("Internal type is not allowed for public and external functions.")); } diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 0a75e55a9..b2b8bfa4c 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -52,21 +52,27 @@ void Compiler::compileContract(ContractDefinition const& _contract, map const& _contracts) { m_context = CompilerContext(); // clear it just in case - initializeContext(_contract, _contracts); - appendFunctionSelector(_contract); - set functions = m_context.getFunctionsWithoutCode(); - while (!functions.empty()) { - for (Declaration const* function: functions) + CompilerContext::LocationSetter locationSetterRunTime(m_context, _contract); + CompilerUtils(m_context).initialiseFreeMemoryPointer(); + initializeContext(_contract, _contracts); + appendFunctionSelector(_contract); + set functions = m_context.getFunctionsWithoutCode(); + while (!functions.empty()) { - m_context.setStackOffset(0); - function->accept(*this); + for (Declaration const* function: functions) + { + m_context.setStackOffset(0); + function->accept(*this); + } + functions = m_context.getFunctionsWithoutCode(); } - functions = m_context.getFunctionsWithoutCode(); } // Swap the runtime context with the creation-time context swap(m_context, m_runtimeContext); + CompilerContext::LocationSetter locationSetterCreationTime(m_context, _contract); + CompilerUtils(m_context).initialiseFreeMemoryPointer(); initializeContext(_contract, _contracts); packIntoContractCreator(_contract, m_runtimeContext); if (m_optimize) @@ -233,31 +239,42 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool m_context << u256(CompilerUtils::dataStartOffset); for (TypePointer const& type: _typeParameters) { - switch (type->getCategory()) + if (type->getCategory() == Type::Category::Array) { - case Type::Category::Array: - if (type->isDynamicallySized()) + auto const& arrayType = dynamic_cast(*type); + if (arrayType.location() == ReferenceType::Location::CallData) { - // put on stack: data_pointer length - CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(256), !_fromMemory); - // stack: data_offset next_pointer - //@todo once we support nested arrays, this offset needs to be dynamic. - m_context << eth::Instruction::SWAP1 << u256(CompilerUtils::dataStartOffset); - m_context << eth::Instruction::ADD; - // stack: next_pointer data_pointer - // retrieve length - CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(256), !_fromMemory, true); - // stack: next_pointer length data_pointer - m_context << eth::Instruction::SWAP2; + if (type->isDynamicallySized()) + { + // put on stack: data_pointer length + CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(256), !_fromMemory); + // stack: data_offset next_pointer + //@todo once we support nested arrays, this offset needs to be dynamic. + m_context << eth::Instruction::SWAP1 << u256(CompilerUtils::dataStartOffset); + m_context << eth::Instruction::ADD; + // stack: next_pointer data_pointer + // retrieve length + CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(256), !_fromMemory, true); + // stack: next_pointer length data_pointer + m_context << eth::Instruction::SWAP2; + } + else + { + // leave the pointer on the stack + m_context << eth::Instruction::DUP1; + m_context << u256(type->getCalldataEncodedSize()) << eth::Instruction::ADD; + } } else { - // leave the pointer on the stack - m_context << eth::Instruction::DUP1; - m_context << u256(type->getCalldataEncodedSize()) << eth::Instruction::ADD; + solAssert(arrayType.location() == ReferenceType::Location::Memory, ""); + CompilerUtils(m_context).fetchFreeMemoryPointer(); + CompilerUtils(m_context).storeInMemoryDynamic(*type); + CompilerUtils(m_context).storeFreeMemoryPointer(); } - break; - default: + } + else + { solAssert(!type->isDynamicallySized(), "Unknown dynamically sized type: " + type->toString()); CompilerUtils(m_context).loadFromMemoryDynamic(*type, !_fromMemory, true); } @@ -281,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/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp index 3549ef98d..7a96db928 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/CompilerUtils.cpp @@ -31,7 +31,31 @@ namespace dev namespace solidity { -const unsigned int CompilerUtils::dataStartOffset = 4; +const unsigned CompilerUtils::dataStartOffset = 4; +const size_t CompilerUtils::freeMemoryPointer = 64; + +void CompilerUtils::initialiseFreeMemoryPointer() +{ + m_context << u256(freeMemoryPointer + 32); + storeFreeMemoryPointer(); +} + +void CompilerUtils::fetchFreeMemoryPointer() +{ + m_context << u256(freeMemoryPointer) << eth::Instruction::MLOAD; +} + +void CompilerUtils::storeFreeMemoryPointer() +{ + m_context << u256(freeMemoryPointer) << eth::Instruction::MSTORE; +} + +void CompilerUtils::toSizeAfterFreeMemoryPointer() +{ + fetchFreeMemoryPointer(); + m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2 << eth::Instruction::SUB; + m_context << eth::Instruction::SWAP1; +} unsigned CompilerUtils::loadFromMemory( unsigned _offset, @@ -187,6 +211,7 @@ unsigned CompilerUtils::getSizeOnStack(vector> const& _va void CompilerUtils::computeHashStatic(Type const& _type, bool _padToWordBoundaries) { unsigned length = storeInMemory(0, _type, _padToWordBoundaries); + solAssert(length <= CompilerUtils::freeMemoryPointer, ""); m_context << u256(length) << u256(0) << eth::Instruction::SHA3; } diff --git a/libsolidity/CompilerUtils.h b/libsolidity/CompilerUtils.h index 45f53e12e..27c46ba11 100644 --- a/libsolidity/CompilerUtils.h +++ b/libsolidity/CompilerUtils.h @@ -35,6 +35,15 @@ class CompilerUtils public: CompilerUtils(CompilerContext& _context): m_context(_context) {} + /// Stores the initial value of the free-memory-pointer at its position; + void initialiseFreeMemoryPointer(); + /// Copies the free memory pointer to the stack. + void fetchFreeMemoryPointer(); + /// Stores the free memory pointer from the stack. + void storeFreeMemoryPointer(); + /// Appends code that transforms memptr to (memptr - free_memptr) memptr + void toSizeAfterFreeMemoryPointer(); + /// Loads data from memory to the stack. /// @param _offset offset in memory (or calldata) /// @param _type data type to load @@ -67,7 +76,7 @@ public: bool _padToWordBoundaries = false ); /// Dynamic version of @see storeInMemory, expects the memory offset below the value on the stack - /// and also updates that. + /// and also updates that. For arrays, only copies the data part. /// Stack pre: memory_offset value... /// Stack post: (memory_offset+length) void storeInMemoryDynamic(Type const& _type, bool _padToWordBoundaries = true); @@ -95,7 +104,10 @@ public: /// Bytes we need to the start of call data. /// - The size in bytes of the function (hash) identifier. - static const unsigned int dataStartOffset; + static const unsigned dataStartOffset; + + /// Position of the free-memory-pointer in memory; + static const size_t freeMemoryPointer; private: /// Prepares the given type for storing in memory by shifting it if necessary. diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index ba80a8ea2..d9b6da14e 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -73,6 +73,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& { if (auto mappingType = dynamic_cast(returnType.get())) { + solAssert(CompilerUtils::freeMemoryPointer >= 0x40, ""); // pop offset m_context << eth::Instruction::POP; // move storage offset to memory. @@ -470,21 +471,28 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) _functionCall.getExpression().accept(*this); solAssert(!function.gasSet(), "Gas limit set for contract creation."); solAssert(function.getReturnParameterTypes().size() == 1, ""); + TypePointers argumentTypes; + for (auto const& arg: arguments) + { + arg->accept(*this); + argumentTypes.push_back(arg->getType()); + } ContractDefinition const& contract = dynamic_cast( *function.getReturnParameterTypes().front()).getContractDefinition(); // copy the contract's code into memory bytes const& bytecode = m_context.getCompiledContract(contract); - m_context << u256(bytecode.size()); + CompilerUtils(m_context).fetchFreeMemoryPointer(); + m_context << u256(bytecode.size()) << eth::Instruction::DUP1; //@todo could be done by actually appending the Assembly, but then we probably need to compile // multiple times. Will revisit once external fuctions are inlined. m_context.appendData(bytecode); - //@todo copy to memory position 0, shift as soon as we use memory - m_context << u256(0) << eth::Instruction::CODECOPY; + m_context << eth::Instruction::DUP4 << eth::Instruction::CODECOPY; - m_context << u256(bytecode.size()); - appendArgumentsCopyToMemory(arguments, function.getParameterTypes()); - // size, offset, endowment - m_context << u256(0); + m_context << eth::Instruction::ADD; + encodeToMemory(argumentTypes, function.getParameterTypes()); + // now on stack: memory_end_ptr + // need: size, offset, endowment + CompilerUtils(m_context).toSizeAfterFreeMemoryPointer(); if (function.valueSet()) m_context << eth::dupInstruction(3); else @@ -546,12 +554,16 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) break; case Location::SHA3: { - // we might compute a sha as part of argumentsAppendCopyToMemory, this is only a hack - // and should be removed once we have a real free memory pointer - m_context << u256(0x40); - appendArgumentsCopyToMemory(arguments, TypePointers(), function.padArguments(), false, true); - m_context << u256(0x40) << eth::Instruction::SWAP1 << eth::Instruction::SUB; - m_context << u256(0x40) << eth::Instruction::SHA3; + TypePointers argumentTypes; + for (auto const& arg: arguments) + { + arg->accept(*this); + argumentTypes.push_back(arg->getType()); + } + CompilerUtils(m_context).fetchFreeMemoryPointer(); + encodeToMemory(argumentTypes, TypePointers(), function.padArguments(), true); + CompilerUtils(m_context).toSizeAfterFreeMemoryPointer(); + m_context << eth::Instruction::SHA3; break; } case Location::Log0: @@ -566,9 +578,15 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) arguments[arg]->accept(*this); appendTypeConversion(*arguments[arg]->getType(), *function.getParameterTypes()[arg], true); } - m_context << u256(0); - appendExpressionCopyToMemory(*function.getParameterTypes().front(), *arguments.front()); - m_context << u256(0) << eth::logInstruction(logNumber); + arguments.front()->accept(*this); + CompilerUtils(m_context).fetchFreeMemoryPointer(); + encodeToMemory( + {arguments.front()->getType()}, + {function.getParameterTypes().front()}, + false, + true); + CompilerUtils(m_context).toSizeAfterFreeMemoryPointer(); + m_context << eth::logInstruction(logNumber); break; } case Location::Event: @@ -582,8 +600,11 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) { ++numIndexed; arguments[arg - 1]->accept(*this); - appendTypeConversion(*arguments[arg - 1]->getType(), - *function.getParameterTypes()[arg - 1], true); + appendTypeConversion( + *arguments[arg - 1]->getType(), + *function.getParameterTypes()[arg - 1], + true + ); } if (!event.isAnonymous()) { @@ -593,18 +614,20 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) solAssert(numIndexed <= 4, "Too many indexed arguments."); // Copy all non-indexed arguments to memory (data) // Memory position is only a hack and should be removed once we have free memory pointer. - m_context << u256(0x40); - vector> nonIndexedArgs; - TypePointers nonIndexedTypes; + TypePointers nonIndexedArgTypes; + TypePointers nonIndexedParamTypes; for (unsigned arg = 0; arg < arguments.size(); ++arg) if (!event.getParameters()[arg]->isIndexed()) { - nonIndexedArgs.push_back(arguments[arg]); - nonIndexedTypes.push_back(function.getParameterTypes()[arg]); + arguments[arg]->accept(*this); + nonIndexedArgTypes.push_back(arguments[arg]->getType()); + nonIndexedParamTypes.push_back(function.getParameterTypes()[arg]); } - appendArgumentsCopyToMemory(nonIndexedArgs, nonIndexedTypes); - m_context << u256(0x40) << eth::Instruction::SWAP1 << eth::Instruction::SUB; - m_context << u256(0x40) << eth::logInstruction(numIndexed); + CompilerUtils(m_context).fetchFreeMemoryPointer(); + encodeToMemory(nonIndexedArgTypes, nonIndexedParamTypes); + // need: topic1 ... topicn memsize memstart + CompilerUtils(m_context).toSizeAfterFreeMemoryPointer(); + m_context << eth::logInstruction(numIndexed); break; } case Location::BlockHash: @@ -804,8 +827,10 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess) Type const& keyType = *dynamic_cast(baseType).getKeyType(); m_context << u256(0); // memory position solAssert(_indexAccess.getIndexExpression(), "Index expression expected."); + solAssert(keyType.getCalldataEncodedSize() <= 0x20, "Dynamic keys not yet implemented."); appendExpressionCopyToMemory(keyType, *_indexAccess.getIndexExpression()); m_context << eth::Instruction::SWAP1; + solAssert(CompilerUtils::freeMemoryPointer >= 0x40, ""); appendTypeMoveToMemory(IntegerType(256)); m_context << u256(0) << eth::Instruction::SHA3; m_context << u256(0); @@ -1058,42 +1083,81 @@ void ExpressionCompiler::appendExternalFunctionCall( unsigned gasStackPos = m_context.currentToBaseStackOffset(gasValueSize); unsigned valueStackPos = m_context.currentToBaseStackOffset(1); - bool returnSuccessCondition = - _functionType.getLocation() == FunctionType::Location::Bare || - _functionType.getLocation() == FunctionType::Location::BareCallCode; + using FunctionKind = FunctionType::Location; + FunctionKind funKind = _functionType.getLocation(); + bool returnSuccessCondition = funKind == FunctionKind::Bare || funKind == FunctionKind::BareCallCode; + //@todo only return the first return value for now - Type const* firstType = _functionType.getReturnParameterTypes().empty() ? nullptr : - _functionType.getReturnParameterTypes().front().get(); - unsigned retSize = firstType ? firstType->getCalldataEncodedSize() : 0; + Type const* firstReturnType = + _functionType.getReturnParameterTypes().empty() ? + nullptr : + _functionType.getReturnParameterTypes().front().get(); + unsigned retSize = firstReturnType ? firstReturnType->getCalldataEncodedSize() : 0; if (returnSuccessCondition) retSize = 0; // return value actually is success condition - m_context << u256(retSize) << u256(0); - if (_functionType.isBareCall()) - m_context << u256(0); - else + // Evaluate arguments. + TypePointers argumentTypes; + bool manualFunctionId = + (funKind == FunctionKind::Bare || funKind == FunctionKind::BareCallCode) && + !_arguments.empty() && + _arguments.front()->getType()->getRealType()->getCalldataEncodedSize(false) == + CompilerUtils::dataStartOffset; + if (manualFunctionId) { - // copy function identifier - m_context << eth::dupInstruction(gasValueSize + 3); - CompilerUtils(m_context).storeInMemory(0, IntegerType(CompilerUtils::dataStartOffset * 8)); - m_context << u256(CompilerUtils::dataStartOffset); + // If we have a BareCall or BareCallCode and the first type has exactly 4 bytes, use it as + // function identifier. + _arguments.front()->accept(*this); + appendTypeConversion( + *_arguments.front()->getType(), + IntegerType(8 * CompilerUtils::dataStartOffset), + true + ); + for (unsigned i = 0; i < gasValueSize; ++i) + m_context << eth::swapInstruction(gasValueSize - i); + gasStackPos++; + valueStackPos++; + } + for (size_t i = manualFunctionId ? 1 : 0; i < _arguments.size(); ++i) + { + _arguments[i]->accept(*this); + argumentTypes.push_back(_arguments[i]->getType()); } - // For bare call, activate "4 byte pad exception": If the first argument has exactly 4 bytes, - // do not pad it to 32 bytes. + // Copy function identifier to memory. + CompilerUtils(m_context).fetchFreeMemoryPointer(); + if (!_functionType.isBareCall() || manualFunctionId) + { + m_context << eth::dupInstruction(2 + gasValueSize + CompilerUtils::getSizeOnStack(argumentTypes)); + appendTypeMoveToMemory(IntegerType(8 * CompilerUtils::dataStartOffset), false); + } // If the function takes arbitrary parameters, copy dynamic length data in place. - appendArgumentsCopyToMemory( - _arguments, + // Move argumenst to memory, will not update the free memory pointer (but will update the memory + // pointer on the stack). + encodeToMemory( + argumentTypes, _functionType.getParameterTypes(), _functionType.padArguments(), - _functionType.getLocation() == FunctionType::Location::Bare || - _functionType.getLocation() == FunctionType::Location::BareCallCode, _functionType.takesArbitraryParameters() ); - // CALL arguments: outSize, outOff, inSize, (already present up to here) - // inOff, value, addr, gas (stack top) - m_context << u256(0); + // Stack now: + // + // input_memory_end + // value [if _functionType.valueSet()] + // gas [if _functionType.gasSet()] + // function identifier [unless bare] + // contract address + + // Output data will replace input data. + // put on stack: + m_context << u256(retSize); + CompilerUtils(m_context).fetchFreeMemoryPointer(); + m_context << eth::Instruction::DUP1 << eth::Instruction::DUP4 << eth::Instruction::SUB; + m_context << eth::Instruction::DUP2; + + // CALL arguments: outSize, outOff, inSize, inOff (already present up to here) + // value, addr, gas (stack top) if (_functionType.valueSet()) m_context << eth::dupInstruction(m_context.baseToCurrentStackOffset(valueStackPos)); else @@ -1109,19 +1173,16 @@ void ExpressionCompiler::appendExternalFunctionCall( u256(eth::c_callGas + 10 + (_functionType.valueSet() ? eth::c_callValueTransferGas : 0) + eth::c_callNewAccountGas) << eth::Instruction::GAS << eth::Instruction::SUB; - if ( - _functionType.getLocation() == FunctionType::Location::CallCode || - _functionType.getLocation() == FunctionType::Location::BareCallCode - ) + if (funKind == FunctionKind::CallCode || funKind == FunctionKind::BareCallCode) m_context << eth::Instruction::CALLCODE; else m_context << eth::Instruction::CALL; unsigned remainsSize = - 1 + // contract address + 2 + // contract address, input_memory_end _functionType.valueSet() + _functionType.gasSet() + - !_functionType.isBareCall(); + (!_functionType.isBareCall() || manualFunctionId); if (returnSuccessCondition) m_context << eth::swapInstruction(remainsSize); @@ -1138,52 +1199,93 @@ void ExpressionCompiler::appendExternalFunctionCall( { // already there } - else if (_functionType.getLocation() == FunctionType::Location::RIPEMD160) + else if (funKind == FunctionKind::RIPEMD160) { // fix: built-in contract returns right-aligned data - CompilerUtils(m_context).loadFromMemory(0, IntegerType(160), false, true); + CompilerUtils(m_context).fetchFreeMemoryPointer(); + CompilerUtils(m_context).loadFromMemoryDynamic(IntegerType(160), false, true, false); appendTypeConversion(IntegerType(160), FixedBytesType(20)); } - else if (firstType) - CompilerUtils(m_context).loadFromMemory(0, *firstType, false, true); + else if (firstReturnType) + { + //@todo manually update free memory pointer if we accept returning memory-stored objects + CompilerUtils(m_context).fetchFreeMemoryPointer(); + CompilerUtils(m_context).loadFromMemoryDynamic(*firstReturnType, false, true, false); + } } -void ExpressionCompiler::appendArgumentsCopyToMemory( - vector> const& _arguments, - TypePointers const& _types, +void ExpressionCompiler::encodeToMemory( + TypePointers const& _givenTypes, + TypePointers const& _targetTypes, bool _padToWordBoundaries, - bool _padExceptionIfFourBytes, bool _copyDynamicDataInPlace ) { - solAssert(_types.empty() || _types.size() == _arguments.size(), ""); - TypePointers types = _types; - if (_types.empty()) - for (ASTPointer const& argument: _arguments) - types.push_back(argument->getType()->getRealType()); - - vector dynamicArguments; - unsigned stackSizeOfDynamicTypes = 0; - for (size_t i = 0; i < _arguments.size(); ++i) + // stack: ... + TypePointers targetTypes = _targetTypes.empty() ? _givenTypes : _targetTypes; + solAssert(targetTypes.size() == _givenTypes.size(), ""); + for (TypePointer& t: targetTypes) + t = t->getRealType()->externalType(); + + // Stack during operation: + // ... ... + // The values dyn_head_i are added during the first loop and they point to the head part + // of the ith dynamic parameter, which is filled once the dynamic parts are processed. + + // store memory start pointer + m_context << eth::Instruction::DUP1; + + unsigned argSize = CompilerUtils::getSizeOnStack(_givenTypes); + unsigned stackPos = 0; // advances through the argument values + unsigned dynPointers = 0; // number of dynamic head pointers on the stack + for (size_t i = 0; i < _givenTypes.size(); ++i) { - _arguments[i]->accept(*this); - TypePointer argType = types[i]->externalType(); - solAssert(!!argType, "Externalable type expected."); - if (argType->isValueType()) - appendTypeConversion(*_arguments[i]->getType(), *argType, true); + TypePointer targetType = targetTypes[i]; + solAssert(!!targetType, "Externalable type expected."); + if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace) + { + // leave end_of_mem as dyn head pointer + m_context << eth::Instruction::DUP1 << u256(32) << eth::Instruction::ADD; + dynPointers++; + } else - argType = _arguments[i]->getType()->getRealType()->externalType(); - solAssert(!!argType, "Externalable type expected."); - bool pad = _padToWordBoundaries; - // Do not pad if the first argument has exactly four bytes - if (i == 0 && pad && _padExceptionIfFourBytes && argType->getCalldataEncodedSize(false) == 4) - pad = false; - if (!_copyDynamicDataInPlace && argType->isDynamicallySized()) { - solAssert(argType->getCategory() == Type::Category::Array, "Unknown dynamic type."); - auto const& arrayType = dynamic_cast(*_arguments[i]->getType()); - // move memory reference to top of stack - CompilerUtils(m_context).moveToStackTop(arrayType.getSizeOnStack()); + CompilerUtils(m_context).copyToStackTop( + argSize - stackPos + dynPointers + 2, + _givenTypes[i]->getSizeOnStack() + ); + if (targetType->isValueType()) + appendTypeConversion(*_givenTypes[i], *targetType, true); + solAssert(!!targetType, "Externalable type expected."); + appendTypeMoveToMemory(*targetType, _padToWordBoundaries); + } + stackPos += _givenTypes[i]->getSizeOnStack(); + } + + // now copy the dynamic part + // Stack: ... ... + stackPos = 0; + unsigned thisDynPointer = 0; + for (size_t i = 0; i < _givenTypes.size(); ++i) + { + TypePointer targetType = targetTypes[i]; + solAssert(!!targetType, "Externalable type expected."); + if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace) + { + solAssert(_givenTypes[i]->getCategory() == Type::Category::Array, "Unknown dynamic type."); + auto const& arrayType = dynamic_cast(*_givenTypes[i]); + // copy tail pointer (=mem_end - mem_start) to memory + m_context << eth::dupInstruction(2 + dynPointers) << eth::Instruction::DUP2; + m_context << eth::Instruction::SUB; + m_context << eth::dupInstruction(2 + dynPointers - thisDynPointer); + m_context << eth::Instruction::MSTORE; + // now copy the array + CompilerUtils(m_context).copyToStackTop( + argSize - stackPos + dynPointers + 2, + arrayType.getSizeOnStack() + ); + // copy length to memory + m_context << eth::dupInstruction(1 + arrayType.getSizeOnStack()); if (arrayType.location() == ReferenceType::Location::CallData) m_context << eth::Instruction::DUP2; // length is on stack else if (arrayType.location() == ReferenceType::Location::Storage) @@ -1194,31 +1296,19 @@ void ExpressionCompiler::appendArgumentsCopyToMemory( m_context << eth::Instruction::DUP2 << eth::Instruction::MLOAD; } appendTypeMoveToMemory(IntegerType(256), true); - stackSizeOfDynamicTypes += arrayType.getSizeOnStack(); - dynamicArguments.push_back(i); - } - else - appendTypeMoveToMemory(*argType, pad); - } + // copy the new memory pointer + m_context << eth::swapInstruction(arrayType.getSizeOnStack() + 1) << eth::Instruction::POP; + // copy data part + appendTypeMoveToMemory(arrayType, true); - // copy dynamic values to memory - unsigned dynStackPointer = stackSizeOfDynamicTypes; - // stack layout: ... - for (size_t i: dynamicArguments) - { - auto const& arrayType = dynamic_cast(*_arguments[i]->getType()); - CompilerUtils(m_context).copyToStackTop(1 + dynStackPointer, arrayType.getSizeOnStack()); - dynStackPointer -= arrayType.getSizeOnStack(); - appendTypeMoveToMemory(arrayType, true); + thisDynPointer++; + } + stackPos += _givenTypes[i]->getSizeOnStack(); } - solAssert(dynStackPointer == 0, ""); - // remove dynamic values (and retain memory pointer) - if (stackSizeOfDynamicTypes > 0) - { - m_context << eth::swapInstruction(stackSizeOfDynamicTypes); - CompilerUtils(m_context).popStackSlots(stackSizeOfDynamicTypes); - } + // remove unneeded stack elements (and retain memory pointer) + m_context << eth::swapInstruction(argSize + dynPointers + 1); + CompilerUtils(m_context).popStackSlots(argSize + dynPointers + 1); } void ExpressionCompiler::appendTypeMoveToMemory(Type const& _type, bool _padToWordBoundaries) diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 174e16d8d..90994dfdb 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -98,21 +98,28 @@ private: void appendHighBitsCleanup(IntegerType const& _typeOnStack); /// Appends code to call a function of the given type with the given arguments. - void appendExternalFunctionCall(FunctionType const& _functionType, std::vector> const& _arguments); - /// Appends code that evaluates the given arguments and moves the result to memory encoded as - /// specified by the ABI. The memory offset is expected to be on the stack and is updated by - /// this call. If @a _padToWordBoundaries is set to false, all values are concatenated without - /// padding. If @a _copyDynamicDataInPlace is set, dynamic types is stored (without length) + void appendExternalFunctionCall( + FunctionType const& _functionType, + std::vector> const& _arguments + ); + /// Copies values (of types @a _givenTypes) given on the stack to a location in memory given + /// at the stack top, encoding them according to the ABI as the given types @a _targetTypes. + /// Removes the values from the stack and leaves the updated memory pointer. + /// Stack pre: ... + /// Stack post: + /// Does not touch the memory-free pointer. + /// @param _padToWordBoundaries if false, all values are concatenated without padding. + /// @param _copyDynamicDataInPlace if true, dynamic types is stored (without length) /// together with fixed-length data. - void appendArgumentsCopyToMemory( - std::vector> const& _arguments, - TypePointers const& _types = {}, + void encodeToMemory( + TypePointers const& _givenTypes = {}, + TypePointers const& _targetTypes = {}, bool _padToWordBoundaries = true, - bool _padExceptionIfFourBytes = false, bool _copyDynamicDataInPlace = false ); /// Appends code that moves a stack element of the given type to memory. The memory offset is /// expected below the stack element and is updated by this call. + /// For arrays, this only copies the data part. void appendTypeMoveToMemory(Type const& _type, bool _padToWordBoundaries = true); /// Appends code that evaluates a single expression and moves the result to memory. The memory offset is /// expected to be on the stack and is updated by this call. diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index 9a2acd5ba..a9d54cdc6 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -16,8 +16,10 @@ InterfaceHandler::InterfaceHandler() m_lastTag = DocTagType::None; } -std::unique_ptr InterfaceHandler::getDocumentation(ContractDefinition const& _contractDef, - DocumentationType _type) +unique_ptr InterfaceHandler::getDocumentation( + ContractDefinition const& _contractDef, + DocumentationType _type +) { switch(_type) { @@ -35,7 +37,7 @@ std::unique_ptr InterfaceHandler::getDocumentation(ContractDefiniti return nullptr; } -std::unique_ptr InterfaceHandler::getABIInterface(ContractDefinition const& _contractDef) +unique_ptr InterfaceHandler::getABIInterface(ContractDefinition const& _contractDef) { Json::Value abi(Json::arrayValue); @@ -101,7 +103,7 @@ std::unique_ptr InterfaceHandler::getABIInterface(ContractDefinitio event["inputs"] = params; abi.append(event); } - return std::unique_ptr(new std::string(Json::FastWriter().write(abi))); + return unique_ptr(new string(Json::FastWriter().write(abi))); } unique_ptr InterfaceHandler::getABISolidityInterface(ContractDefinition const& _contractDef) @@ -141,7 +143,7 @@ unique_ptr InterfaceHandler::getABISolidityInterface(ContractDefinition return unique_ptr(new string(ret + "}")); } -std::unique_ptr InterfaceHandler::getUserDocumentation(ContractDefinition const& _contractDef) +unique_ptr InterfaceHandler::getUserDocumentation(ContractDefinition const& _contractDef) { Json::Value doc; Json::Value methods(Json::objectValue); @@ -163,10 +165,10 @@ std::unique_ptr InterfaceHandler::getUserDocumentation(ContractDefi } doc["methods"] = methods; - return std::unique_ptr(new std::string(Json::FastWriter().write(doc))); + return unique_ptr(new string(Json::FastWriter().write(doc))); } -std::unique_ptr InterfaceHandler::getDevDocumentation(ContractDefinition const& _contractDef) +unique_ptr InterfaceHandler::getDevDocumentation(ContractDefinition const& _contractDef) { // LTODO: Somewhere in this function warnings for mismatch of param names // should be thrown @@ -203,7 +205,7 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(ContractDefin method["author"] = m_author; Json::Value params(Json::objectValue); - std::vector paramNames = it.second->getParameterNames(); + vector paramNames = it.second->getParameterNames(); for (auto const& pair: m_params) { if (find(paramNames.begin(), paramNames.end(), pair.first) == paramNames.end()) @@ -227,7 +229,7 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(ContractDefin } doc["methods"] = methods; - return std::unique_ptr(new std::string(Json::FastWriter().write(doc))); + return unique_ptr(new string(Json::FastWriter().write(doc))); } /* -- private -- */ @@ -244,48 +246,56 @@ void InterfaceHandler::resetDev() m_params.clear(); } -static inline std::string::const_iterator skipLineOrEOS(std::string::const_iterator _nlPos, - std::string::const_iterator _end) +static inline string::const_iterator skipLineOrEOS( + string::const_iterator _nlPos, + string::const_iterator _end +) { return (_nlPos == _end) ? _end : ++_nlPos; } -std::string::const_iterator InterfaceHandler::parseDocTagLine(std::string::const_iterator _pos, - std::string::const_iterator _end, - std::string& _tagString, - DocTagType _tagType, - bool _appending) +string::const_iterator InterfaceHandler::parseDocTagLine( + string::const_iterator _pos, + string::const_iterator _end, + string& _tagString, + DocTagType _tagType, + bool _appending +) { - auto nlPos = std::find(_pos, _end, '\n'); + auto nlPos = find(_pos, _end, '\n'); if (_appending && _pos < _end && *_pos != ' ') _tagString += " "; - std::copy(_pos, nlPos, back_inserter(_tagString)); + copy(_pos, nlPos, back_inserter(_tagString)); m_lastTag = _tagType; return skipLineOrEOS(nlPos, _end); } -std::string::const_iterator InterfaceHandler::parseDocTagParam(std::string::const_iterator _pos, - std::string::const_iterator _end) +string::const_iterator InterfaceHandler::parseDocTagParam( + string::const_iterator _pos, + string::const_iterator _end +) { // find param name - auto currPos = std::find(_pos, _end, ' '); + auto currPos = find(_pos, _end, ' '); if (currPos == _end) - BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("End of param name not found" + std::string(_pos, _end))); + BOOST_THROW_EXCEPTION(DocstringParsingError() << errinfo_comment("End of param name not found" + string(_pos, _end))); - auto paramName = std::string(_pos, currPos); + auto paramName = string(_pos, currPos); currPos += 1; - auto nlPos = std::find(currPos, _end, '\n'); - auto paramDesc = std::string(currPos, nlPos); - m_params.push_back(std::make_pair(paramName, paramDesc)); + auto nlPos = find(currPos, _end, '\n'); + auto paramDesc = string(currPos, nlPos); + m_params.push_back(make_pair(paramName, paramDesc)); m_lastTag = DocTagType::Param; return skipLineOrEOS(nlPos, _end); } -std::string::const_iterator InterfaceHandler::appendDocTagParam(std::string::const_iterator _pos, - std::string::const_iterator _end) +string::const_iterator InterfaceHandler::appendDocTagParam( + string::const_iterator _pos, + string::const_iterator _end +) { // Should never be called with an empty vector solAssert(!m_params.empty(), "Internal: Tried to append to empty parameter"); @@ -293,18 +303,20 @@ std::string::const_iterator InterfaceHandler::appendDocTagParam(std::string::con auto pair = m_params.back(); if (_pos < _end && *_pos != ' ') pair.second += " "; - auto nlPos = std::find(_pos, _end, '\n'); - std::copy(_pos, nlPos, back_inserter(pair.second)); + auto nlPos = find(_pos, _end, '\n'); + copy(_pos, nlPos, back_inserter(pair.second)); m_params.at(m_params.size() - 1) = pair; return skipLineOrEOS(nlPos, _end); } -std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_iterator _pos, - std::string::const_iterator _end, - std::string const& _tag, - CommentOwner _owner) +string::const_iterator InterfaceHandler::parseDocTag( + string::const_iterator _pos, + string::const_iterator _end, + string const& _tag, + CommentOwner _owner +) { // LTODO: need to check for @(start of a tag) between here and the end of line // for all cases. Also somehow automate list of acceptable tags for each @@ -345,9 +357,11 @@ std::string::const_iterator InterfaceHandler::parseDocTag(std::string::const_ite return appendDocTag(_pos, _end, _owner); } -std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_iterator _pos, - std::string::const_iterator _end, - CommentOwner _owner) +string::const_iterator InterfaceHandler::appendDocTag( + string::const_iterator _pos, + string::const_iterator _end, + CommentOwner _owner +) { switch (m_lastTag) { @@ -379,33 +393,36 @@ std::string::const_iterator InterfaceHandler::appendDocTag(std::string::const_it } } -static inline std::string::const_iterator getFirstSpaceOrNl(std::string::const_iterator _pos, - std::string::const_iterator _end) +static inline string::const_iterator getFirstSpaceOrNl( + string::const_iterator _pos, + string::const_iterator _end +) { - auto spacePos = std::find(_pos, _end, ' '); - auto nlPos = std::find(_pos, _end, '\n'); + auto spacePos = find(_pos, _end, ' '); + auto nlPos = find(_pos, _end, '\n'); return (spacePos < nlPos) ? spacePos : nlPos; } -void InterfaceHandler::parseDocString(std::string const& _string, CommentOwner _owner) +void InterfaceHandler::parseDocString(string const& _string, CommentOwner _owner) { auto currPos = _string.begin(); auto end = _string.end(); while (currPos != end) { - auto tagPos = std::find(currPos, end, '@'); - auto nlPos = std::find(currPos, end, '\n'); + auto tagPos = find(currPos, end, '@'); + auto nlPos = find(currPos, end, '\n'); if (tagPos != end && tagPos < nlPos) { // we found a tag auto tagNameEndPos = getFirstSpaceOrNl(tagPos, end); if (tagNameEndPos == end) - BOOST_THROW_EXCEPTION(DocstringParsingError() << - errinfo_comment("End of tag " + std::string(tagPos, tagNameEndPos) + "not found")); + BOOST_THROW_EXCEPTION( + DocstringParsingError() << + errinfo_comment("End of tag " + string(tagPos, tagNameEndPos) + "not found")); - currPos = parseDocTag(tagNameEndPos + 1, end, std::string(tagPos + 1, tagNameEndPos), _owner); + currPos = parseDocTag(tagNameEndPos + 1, end, string(tagPos + 1, tagNameEndPos), _owner); } else if (m_lastTag != DocTagType::None) // continuation of the previous tag currPos = appendDocTag(currPos, end, _owner); diff --git a/libsolidity/InterfaceHandler.h b/libsolidity/InterfaceHandler.h index 405181890..ca9807d7e 100644 --- a/libsolidity/InterfaceHandler.h +++ b/libsolidity/InterfaceHandler.h @@ -67,8 +67,10 @@ public: /// types provided by @c DocumentationType /// @return A unique pointer contained string with the json /// representation of provided type - std::unique_ptr getDocumentation(ContractDefinition const& _contractDef, - DocumentationType _type); + std::unique_ptr getDocumentation( + ContractDefinition const& _contractDef, + DocumentationType _type + ); /// Get the ABI Interface of the contract /// @param _contractDef The contract definition /// @return A unique pointer contained string with the json @@ -90,23 +92,33 @@ private: void resetUser(); void resetDev(); - std::string::const_iterator parseDocTagLine(std::string::const_iterator _pos, - std::string::const_iterator _end, - std::string& _tagString, - DocTagType _tagType, - bool _appending); - std::string::const_iterator parseDocTagParam(std::string::const_iterator _pos, - std::string::const_iterator _end); - std::string::const_iterator appendDocTagParam(std::string::const_iterator _pos, - std::string::const_iterator _end); + std::string::const_iterator parseDocTagLine( + std::string::const_iterator _pos, + std::string::const_iterator _end, + std::string& _tagString, + DocTagType _tagType, + bool _appending + ); + std::string::const_iterator parseDocTagParam( + std::string::const_iterator _pos, + std::string::const_iterator _end + ); + std::string::const_iterator appendDocTagParam( + std::string::const_iterator _pos, + std::string::const_iterator _end + ); void parseDocString(std::string const& _string, CommentOwner _owner); - std::string::const_iterator appendDocTag(std::string::const_iterator _pos, - std::string::const_iterator _end, - CommentOwner _owner); - std::string::const_iterator parseDocTag(std::string::const_iterator _pos, - std::string::const_iterator _end, - std::string const& _tag, - CommentOwner _owner); + std::string::const_iterator appendDocTag( + std::string::const_iterator _pos, + std::string::const_iterator _end, + CommentOwner _owner + ); + std::string::const_iterator parseDocTag( + std::string::const_iterator _pos, + std::string::const_iterator _end, + std::string const& _tag, + CommentOwner _owner + ); // internal state DocTagType m_lastTag; diff --git a/libsolidity/Token.h b/libsolidity/Token.h index 3e8c1c1d1..43a5b90b9 100644 --- a/libsolidity/Token.h +++ b/libsolidity/Token.h @@ -253,7 +253,6 @@ namespace solidity K(UInt240, "uint240", 0) \ K(UInt248, "uint248", 0) \ K(UInt256, "uint256", 0) \ - K(Bytes0, "bytes0", 0) \ K(Bytes1, "bytes1", 0) \ K(Bytes2, "bytes2", 0) \ K(Bytes3, "bytes3", 0) \ @@ -306,7 +305,7 @@ namespace solidity /* Identifiers (not keywords or future reserved words). */ \ T(Identifier, NULL, 0) \ \ - /* Keywords reserved for future. use*/ \ + /* Keywords reserved for future. use. */ \ K(As, "as", 0) \ K(Case, "case", 0) \ K(Catch, "catch", 0) \ diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index e1161c3fb..6f16f5193 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -121,7 +121,7 @@ TypePointer Type::fromElementaryTypeName(Token::Value _typeToken) { int offset = _typeToken - Token::Int; int bytes = offset % 33; - if (bytes == 0 && _typeToken != Token::Bytes0) + if (bytes == 0 && _typeToken != Token::Bytes1) bytes = 32; int modifier = offset / 33; switch(modifier) @@ -131,7 +131,7 @@ TypePointer Type::fromElementaryTypeName(Token::Value _typeToken) case 1: return make_shared(bytes * 8, IntegerType::Modifier::Unsigned); case 2: - return make_shared(bytes); + return make_shared(bytes + 1); default: solAssert(false, "Unexpected modifier value. Should never happen"); return TypePointer(); diff --git a/libweb3jsonrpc/WebThreeStubServer.cpp b/libweb3jsonrpc/WebThreeStubServer.cpp index 44f7f521c..1bef71b59 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,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 1eddc22d4..8bdeb6b7a 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -33,19 +33,33 @@ namespace dev { class WebThreeDirect; +namespace eth +{ +class KeyManager; +} } +struct SessionPermissions +{ + bool admin; +}; + /** * @brief JSON-RPC api implementation for 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; + 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 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; virtual dev::WebThreeNetworkFace* network() override; @@ -54,9 +68,15 @@ 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); + virtual Json::Value admin_eth_blockQueueStatus(std::string const& _session); + private: dev::WebThreeDirect& m_web3; + dev::eth::KeyManager& m_keyMan; leveldb::ReadOptions m_readOptions; leveldb::WriteOptions m_writeOptions; leveldb::DB* m_db; + + std::unordered_map m_sessions; }; diff --git a/libweb3jsonrpc/WebThreeStubServerBase.cpp b/libweb3jsonrpc/WebThreeStubServerBase.cpp index fa07e7dd3..f88443ee5 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.cpp +++ b/libweb3jsonrpc/WebThreeStubServerBase.cpp @@ -164,15 +164,33 @@ static Json::Value toJson(dev::eth::Transaction const& _t) static Json::Value toJson(dev::eth::LocalisedLogEntry const& _e) { Json::Value res; - if (_e.transactionHash) + if (_e.topics.size() > 0) { res["data"] = toJS(_e.data); res["address"] = toJS(_e.address); res["topics"] = Json::Value(Json::arrayValue); for (auto const& t: _e.topics) res["topics"].append(toJS(t)); - res["number"] = _e.number; - res["hash"] = toJS(_e.transactionHash); + if (_e.mined) + { + res["type"] = "mined"; + res["blockNumber"] = _e.blockNumber; + res["blockHash"] = toJS(_e.blockHash); + res["logIndex"] = _e.logIndex; + res["transactionHash"] = toJS(_e.transactionHash); + res["transactionIndex"] = _e.transactionIndex; + } + else + { + res["type"] = "pending"; + res["blockNumber"] = Json::Value(Json::nullValue); + res["blockHash"] = Json::Value(Json::nullValue); + res["logIndex"] = Json::Value(Json::nullValue); + res["transactionHash"] = Json::Value(Json::nullValue); + res["transactionIndex"] = Json::Value(Json::nullValue); + } + } else { + res = toJS(_e.special); } return res; } @@ -193,7 +211,42 @@ static Json::Value toJson(map const& _storage) return res; } -static dev::eth::LogFilter toLogFilter(Json::Value const& _json) // commented to avoid warning. Uncomment once in use @ PoC-7. +static dev::eth::LogFilter toLogFilter(Json::Value const& _json) +{ + dev::eth::LogFilter filter; + if (!_json.isObject() || _json.empty()) + return filter; + + // check only !empty. it should throw exceptions if input params are incorrect + if (!_json["fromBlock"].empty()) + filter.withEarliest(jsToFixed<32>(_json["fromBlock"].asString())); + if (!_json["toBlock"].empty()) + filter.withLatest(jsToFixed<32>(_json["toBlock"].asString())); + if (!_json["address"].empty()) + { + if (_json["address"].isArray()) + for (auto i : _json["address"]) + filter.address(jsToAddress(i.asString())); + else + filter.address(jsToAddress(_json["address"].asString())); + } + if (!_json["topics"].empty()) + for (unsigned i = 0; i < _json["topics"].size(); i++) + { + if (_json["topics"][i].isArray()) + { + for (auto t: _json["topics"][i]) + if (!t.isNull()) + filter.topic(i, jsToFixed<32>(t.asString())); + } + else if (!_json["topics"][i].isNull()) // if it is anything else then string, it should and will fail + filter.topic(i, jsToFixed<32>(_json["topics"][i].asString())); + } + return filter; +} + +// TODO: this should be removed once we decide to remove backward compatibility with old log filters +static dev::eth::LogFilter toLogFilter(Json::Value const& _json, Interface const& _client) // commented to avoid warning. Uncomment once in use @ PoC-7. { dev::eth::LogFilter filter; if (!_json.isObject() || _json.empty()) @@ -201,9 +254,9 @@ static dev::eth::LogFilter toLogFilter(Json::Value const& _json) // commented to // check only !empty. it should throw exceptions if input params are incorrect if (!_json["fromBlock"].empty()) - filter.withEarliest(jsToBlockNumber(_json["fromBlock"].asString())); + filter.withEarliest(_client.hashFromNumber(jsToBlockNumber(_json["fromBlock"].asString()))); if (!_json["toBlock"].empty()) - filter.withLatest(jsToBlockNumber(_json["toBlock"].asString())); + filter.withLatest(_client.hashFromNumber(jsToBlockNumber(_json["toBlock"].asString()))); if (!_json["address"].empty()) { if (_json["address"].isArray()) @@ -712,25 +765,24 @@ Json::Value WebThreeStubServerBase::eth_getCompilers() } -string WebThreeStubServerBase::eth_compileLLL(string const& _code) +string WebThreeStubServerBase::eth_compileLLL(string const& _source) { // TODO throw here jsonrpc errors string res; vector errors; - res = toJS(dev::eth::compileLLL(_code, true, &errors)); + res = toJS(dev::eth::compileLLL(_source, true, &errors)); cwarn << "LLL compilation errors: " << errors; return res; } -string WebThreeStubServerBase::eth_compileSerpent(string const& _code) +string WebThreeStubServerBase::eth_compileSerpent(string const& _source) { // TODO throw here jsonrpc errors string res; - (void)_code; #if ETH_SERPENT || !ETH_TRUE try { - res = toJS(dev::asBytes(::compile(_code))); + res = toJS(dev::asBytes(::compile(_source))); } catch (string err) { @@ -740,36 +792,151 @@ string WebThreeStubServerBase::eth_compileSerpent(string const& _code) { cwarn << "Uncought serpent compilation exception"; } +#else + (void)_source; #endif return res; } -string WebThreeStubServerBase::eth_compileSolidity(string const& _code) +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 - (void)_code; - string res; + Json::Value res(Json::objectValue); #if ETH_SOLIDITY || !ETH_TRUE dev::solidity::CompilerStack compiler; try { - res = toJS(compiler.compile(_code, true)); + compiler.addSource("source", _source); + compiler.compile(); + + for (string const& name: compiler.getContractNames()) + { + Json::Value contract(Json::objectValue); + contract["code"] = toJS(compiler.getBytecode(name)); + + Json::Value info(Json::objectValue); + info["source"] = _source; + info["language"] = ""; + info["languageVersion"] = ""; + info["compilerVersion"] = ""; + + Json::Reader reader; + reader.parse(compiler.getInterface(name), info["abiDefinition"]); + reader.parse(compiler.getMetadata(name, dev::solidity::DocumentationType::NatspecUser), info["userDoc"]); + reader.parse(compiler.getMetadata(name, dev::solidity::DocumentationType::NatspecDev), info["developerDoc"]); + + contract["info"] = info; + res[name] = contract; + } } catch (dev::Exception const& exception) { ostringstream error; solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler); cwarn << "Solidity compilation error: " << error.str(); + return Json::Value(Json::objectValue); } catch (...) { cwarn << "Uncought solidity compilation exception"; + return Json::Value(Json::objectValue); } +#else + (void)_source; #endif return res; } string WebThreeStubServerBase::eth_newFilter(Json::Value const& _json) +{ + try + { + return toJS(client()->installWatch(toLogFilter(_json, *client()))); + } + catch (...) + { + BOOST_THROW_EXCEPTION(JsonRpcException(Errors::ERROR_RPC_INVALID_PARAMS)); + } +} + +string WebThreeStubServerBase::eth_newFilterEx(Json::Value const& _json) { try { @@ -823,6 +990,22 @@ Json::Value WebThreeStubServerBase::eth_getFilterChanges(string const& _filterId } } +Json::Value WebThreeStubServerBase::eth_getFilterChangesEx(string const& _filterId) +{ + try + { + int id = jsToInt(_filterId); + auto entries = client()->checkWatch(id); + if (entries.size()) + cnote << "FIRING WATCH" << id << entries.size(); + return toJson(entries); + } + catch (...) + { + BOOST_THROW_EXCEPTION(JsonRpcException(Errors::ERROR_RPC_INVALID_PARAMS)); + } +} + Json::Value WebThreeStubServerBase::eth_getFilterLogs(string const& _filterId) { try @@ -835,6 +1018,18 @@ Json::Value WebThreeStubServerBase::eth_getFilterLogs(string const& _filterId) } } +Json::Value WebThreeStubServerBase::eth_getFilterLogsEx(string const& _filterId) +{ + try + { + return toJson(client()->logs(jsToInt(_filterId))); + } + catch (...) + { + BOOST_THROW_EXCEPTION(JsonRpcException(Errors::ERROR_RPC_INVALID_PARAMS)); + } +} + Json::Value WebThreeStubServerBase::eth_getLogs(Json::Value const& _json) { try @@ -980,7 +1175,6 @@ string WebThreeStubServerBase::shh_addToGroup(string const& _group, string const string WebThreeStubServerBase::shh_newFilter(Json::Value const& _json) { - try { pair w = toWatch(_json); diff --git a/libweb3jsonrpc/WebThreeStubServerBase.h b/libweb3jsonrpc/WebThreeStubServerBase.h index d90df1445..aaf0a6096 100644 --- a/libweb3jsonrpc/WebThreeStubServerBase.h +++ b/libweb3jsonrpc/WebThreeStubServerBase.h @@ -60,8 +60,6 @@ public: /** * @brief JSON-RPC api implementation - * @todo filters should work on unsigned instead of int - * unsigned are not supported in json-rpc-cpp and there are bugs with double in json-rpc-cpp version 0.2.1 * @todo split these up according to subprotocol (eth, shh, db, p2p, web3) and make it /very/ clear about how to add other subprotocols. * @todo modularise everything so additional subprotocols don't need to change this file. */ @@ -105,13 +103,16 @@ public: virtual Json::Value eth_getCompilers(); virtual std::string eth_compileLLL(std::string const& _s); virtual std::string eth_compileSerpent(std::string const& _s); - virtual std::string eth_compileSolidity(std::string const& _code); + virtual Json::Value eth_compileSolidity(std::string const& _code); virtual std::string eth_newFilter(Json::Value const& _json); + virtual std::string eth_newFilterEx(Json::Value const& _json); virtual std::string eth_newBlockFilter(); virtual std::string eth_newPendingTransactionFilter(); virtual bool eth_uninstallFilter(std::string const& _filterId); virtual Json::Value eth_getFilterChanges(std::string const& _filterId); + virtual Json::Value eth_getFilterChangesEx(std::string const& _filterId); virtual Json::Value eth_getFilterLogs(std::string const& _filterId); + virtual Json::Value eth_getFilterLogsEx(std::string const& _filterId); virtual Json::Value eth_getLogs(Json::Value const& _json); virtual Json::Value eth_getWork(); virtual bool eth_submitWork(std::string const& _nonce, std::string const&, std::string const& _mixHash); @@ -121,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); @@ -134,11 +136,37 @@ 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 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 6a1a3df10..6b94c31da 100644 --- a/libweb3jsonrpc/abstractwebthreestubserver.h +++ b/libweb3jsonrpc/abstractwebthreestubserver.h @@ -45,13 +45,16 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServerbindAndAddMethod(jsonrpc::Procedure("eth_getCompilers", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_getCompilersI); this->bindAndAddMethod(jsonrpc::Procedure("eth_compileLLL", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_compileLLLI); this->bindAndAddMethod(jsonrpc::Procedure("eth_compileSerpent", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_compileSerpentI); - this->bindAndAddMethod(jsonrpc::Procedure("eth_compileSolidity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_compileSolidityI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_compileSolidity", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_OBJECT, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_compileSolidityI); this->bindAndAddMethod(jsonrpc::Procedure("eth_newFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_newFilterI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_newFilterEx", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_newFilterExI); this->bindAndAddMethod(jsonrpc::Procedure("eth_newBlockFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_newBlockFilterI); this->bindAndAddMethod(jsonrpc::Procedure("eth_newPendingTransactionFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_newPendingTransactionFilterI); this->bindAndAddMethod(jsonrpc::Procedure("eth_uninstallFilter", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_uninstallFilterI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getFilterChanges", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getFilterChangesI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_getFilterChangesEx", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getFilterChangesExI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getFilterLogs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getFilterLogsI); + this->bindAndAddMethod(jsonrpc::Procedure("eth_getFilterLogsEx", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_getFilterLogsExI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getLogs", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, "param1",jsonrpc::JSON_OBJECT, NULL), &AbstractWebThreeStubServer::eth_getLogsI); this->bindAndAddMethod(jsonrpc::Procedure("eth_getWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_ARRAY, NULL), &AbstractWebThreeStubServer::eth_getWorkI); this->bindAndAddMethod(jsonrpc::Procedure("eth_submitWork", jsonrpc::PARAMS_BY_POSITION, jsonrpc::JSON_BOOLEAN, "param1",jsonrpc::JSON_STRING,"param2",jsonrpc::JSON_STRING,"param3",jsonrpc::JSON_STRING, NULL), &AbstractWebThreeStubServer::eth_submitWorkI); @@ -61,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); @@ -72,6 +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) @@ -227,6 +253,10 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServereth_newFilter(request[0u]); } + inline virtual void eth_newFilterExI(const Json::Value &request, Json::Value &response) + { + response = this->eth_newFilterEx(request[0u]); + } inline virtual void eth_newBlockFilterI(const Json::Value &request, Json::Value &response) { (void)request; @@ -245,10 +275,18 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServereth_getFilterChanges(request[0u].asString()); } + inline virtual void eth_getFilterChangesExI(const Json::Value &request, Json::Value &response) + { + response = this->eth_getFilterChangesEx(request[0u].asString()); + } inline virtual void eth_getFilterLogsI(const Json::Value &request, Json::Value &response) { response = this->eth_getFilterLogs(request[0u].asString()); } + inline virtual void eth_getFilterLogsExI(const Json::Value &request, Json::Value &response) + { + response = this->eth_getFilterLogsEx(request[0u].asString()); + } inline virtual void eth_getLogsI(const Json::Value &request, Json::Value &response) { response = this->eth_getLogs(request[0u]); @@ -286,6 +324,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()); @@ -331,6 +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; @@ -364,13 +494,16 @@ class AbstractWebThreeStubServer : public jsonrpc::AbstractServer #include #include +#include #include "DebuggingStateWrapper.h" #include "Exceptions.h" #include "QContractDefinition.h" @@ -82,7 +83,6 @@ 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()); @@ -111,7 +111,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,15 +206,17 @@ 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(); + onStateReset(); + WriteGuard(x_queueTransactions); + m_running = true; - unordered_map accounts; - std::vector userAccounts; + QVariantList blocks = _scenario.value("blocks").toList(); + QVariantList stateAccounts = _scenario.value("accounts").toList(); + m_accounts.clear(); + m_accountsSecret.clear(); for (auto const& b: stateAccounts) { QVariantMap account = b.toMap(); @@ -222,7 +224,7 @@ void ClientModel::setupState(QVariantMap _state) 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")) @@ -230,29 +232,70 @@ void ClientModel::setupState(QVariantMap _state) if (!address) continue; - accounts[address] = Account(qvariant_cast(account.value("balance"))->toU256Wei(), Account::NormalCreation); + m_accounts[address] = Account(qvariant_cast(account.value("balance"))->toU256Wei(), Account::NormalCreation); } - for (auto const& c: stateContracts) + m_ethAccounts->setAccounts(m_accountsSecret); + + bool trToExecute = false; + for (auto const& b: blocks) { - 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; + QVariantList transactions = b.toMap().value("transactions").toList(); + m_queueTransactions.push_back(transactions); + trToExecute = transactions.size() > 0; } + m_client->resetState(m_accounts, Secret(_scenario.value("miner").toMap().value("secret").toString().toStdString())); + if (m_queueTransactions.count() > 0 && trToExecute) + { + 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); + disconnect(this, &ClientModel::runStateChanged, this, &ClientModel::finalizeBlock); + disconnect(this, &ClientModel::runFailed, this, &ClientModel::stopExecution); + m_running = false; +} + +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 + { + stopExecution(); + emit runComplete(); + } +} + +void ClientModel::processNextTransactions() +{ + WriteGuard(x_queueTransactions); vector transactionSequence; - for (auto const& t: transactions) + for (auto const& t: m_queueTransactions.front()) { 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 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(); @@ -260,7 +303,8 @@ void ClientModel::setupState(QVariantMap _state) 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") @@ -268,35 +312,27 @@ void ClientModel::setupState(QVariantMap _state) transactionSequence.push_back(transactionSettings); } - m_ethAccounts->setAccounts(userAccounts); - executeSequence(transactionSequence, accounts, Secret(_state.value("miner").toMap().value("secret").toString().toStdString())); + executeSequence(transactionSequence); } -void ClientModel::executeSequence(vector const& _sequence, std::unordered_map const& _accounts, Secret const& _miner) +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(); - - m_client->resetState(_accounts, _miner); //run sequence m_runFuture = QtConcurrent::run([=]() { try { - vector
    deployedContracts; - onStateReset(); 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); @@ -319,12 +355,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; - } if (!transaction.functionId.isEmpty()) encoder.encode(f); for (QVariableDeclaration const* p: f->parametersList()) @@ -334,7 +365,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()); } @@ -344,8 +375,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(); @@ -355,18 +385,12 @@ 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); } m_gasCosts.append(m_client->lastExecution().gasUsed); onNewTransaction(); } - m_running = false; emit runComplete(); } catch(boost::exception const&) @@ -379,37 +403,54 @@ void ClientModel::executeSequence(vector const& _sequence, cerr << boost::current_exception_diagnostic_information(); emit runFailed(e.what()); } - m_running = false; emit runStateChanged(); }); } +void ClientModel::executeTr(QVariantMap _tr) +{ + WriteGuard(x_queueTransactions); + QVariantList trs; + trs.push_back(_tr); + m_queueTransactions.push_back(trs); + if (!m_running) + { + m_running = true; + setupExecutionChain(); + 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()); + } + if (_contractId.startsWith("0x")) + ret = std::make_pair(_contractId, -2); + 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(_contracts.at(_value.second).ref())); + 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())); 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; - return ret; + std::pair ret; + ret.first = _value; + ret.second = m_contractAddresses.size(); + return ret; } void ClientModel::showDebugger() @@ -633,7 +674,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(), QVariantList()); QQmlEngine::setObjectOwnership(record, QQmlEngine::JavaScriptOwnership); return record; } @@ -644,6 +685,7 @@ void ClientModel::onStateReset() m_contractNames.clear(); m_stdContractAddresses.clear(); m_stdContractNames.clear(); + m_queueTransactions.clear(); emit stateCleared(); } @@ -692,27 +734,110 @@ void ClientModel::onNewTransaction() Address contractAddress = (bool)tr.address ? tr.address : tr.contractAddress; auto contractAddressIter = m_contractNames.find(contractAddress); + 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(); + if (creation) + function = contract; if (abi) { QFunctionDefinition const* funcDef = def->getFunction(functionHash); 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)); } } + + // Fill generated logs and decode parameters + for (auto const& log: tr.logs) + { + 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; + 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; + 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; + + 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); + 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 e1648b78d..b5b783b3d 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,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) public: enum RecordType @@ -118,8 +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): - 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, 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; @@ -132,6 +143,10 @@ private: bool m_call; RecordType m_type; QString m_gasUsed; + QString m_sender; + QString m_label; + QVariantMap m_inputParameters; + QVariantList m_logs; }; /** @@ -170,9 +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); + 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 @@ -224,17 +241,21 @@ 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(); 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; @@ -243,12 +264,16 @@ private: std::unique_ptr m_rpcConnector; 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; std::map m_stdContractAddresses; std::map m_stdContractNames; CodeModel* m_codeModel = nullptr; + QList m_queueTransactions; + mutable boost::shared_mutex x_queueTransactions; }; } diff --git a/mix/ContractCallDataEncoder.cpp b/mix/ContractCallDataEncoder.cpp index 07ab8dd73..d805822aa 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,12 @@ QVariant ContractCallDataEncoder::decode(SolidityType const& _type, bytes const& BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Parameter declaration not found")); } +QString ContractCallDataEncoder::decode(QVariableDeclaration* const& _param, bytes _value) +{ + SolidityType const& type = _param->type()->type(); + return decode(type, _value).toString(); +} + QStringList ContractCallDataEncoder::decode(QList const& _returnParameters, bytes _value) { bytesConstRef value(&_value); diff --git a/mix/ContractCallDataEncoder.h b/mix/ContractCallDataEncoder.h index 2707845ae..8fcc65c0a 100644 --- a/mix/ContractCallDataEncoder.h +++ b/mix/ContractCallDataEncoder.h @@ -48,6 +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 _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 2a88d83bf..9a9acecf4 100644 --- a/mix/MachineStates.h +++ b/mix/MachineStates.h @@ -37,57 +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; + 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 c69619fcd..e2e554cb9 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -22,6 +22,7 @@ #include "MixClient.h" #include +#include #include #include #include @@ -58,9 +59,9 @@ 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)); + << 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(); @@ -78,9 +79,13 @@ MixClient::~MixClient() void MixClient::resetState(std::unordered_map const& _accounts, Secret const& _miner) { + WriteGuard l(x_state); Guard fl(x_filtersWatches); + m_filters.clear(); + for (auto& i: m_specialFilters) + i.second.clear(); m_watches.clear(); m_stateDB = OverlayDB(); @@ -183,19 +188,19 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c levels.resize(ext.depth); machineStates.push_back(MachineState{ - steps, - vm.curPC(), - inst, - newMemSize, - static_cast(gas), - vm.stack(), - vm.memory(), - gasCost, - ext.state().storage(ext.myAddress), - std::move(levels), - codeIndex, - dataIndex - }); + steps, + vm.curPC(), + inst, + newMemSize, + static_cast(gas), + vm.stack(), + vm.memory(), + gasCost, + ext.state().storage(ext.myAddress), + std::move(levels), + codeIndex, + dataIndex + }); }; execution.go(onOp); @@ -217,7 +222,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c 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 + //these should not happen in mix case TransactionException::Unknown: case TransactionException::BadInstruction: case TransactionException::BadJumpDestination: @@ -228,6 +233,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c } ExecutionResult d; + d.inputParameters = t.data(); d.result = er; d.machineStates = machineStates; d.executionCode = std::move(codes); @@ -246,28 +252,19 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c if (!_call) { t = _gasAuto ? replaceGas(_t, d.gasUsed, _secret) : _t; - er =_state.execute(lastHashes, 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); + LocalisedLogEntries logs; + TransactionReceipt const& tr = _state.receipt(_state.pending().size() - 1); + + //auto trHash = _state.pending().at(_state.pending().size() - 1).sha3(); + LogEntries le = tr.log(); + if (le.size()) + for (unsigned j = 0; j < le.size(); ++j) + logs.insert(logs.begin(), LocalisedLogEntry(le[j])); + d.logs = logs; } WriteGuard l(x_executions); m_executions.emplace_back(std::move(d)); @@ -282,7 +279,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 @@ -369,20 +365,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 ea6416ac4..afb9f5430 100644 --- a/mix/MixClient.h +++ b/mix/MixClient.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include "MachineStates.h" @@ -88,7 +89,6 @@ 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; diff --git a/mix/QContractDefinition.cpp b/mix/QContractDefinition.cpp index 51b37e399..f4022d1ff 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..1a1dd8083 100644 --- a/mix/QFunctionDefinition.cpp +++ b/mix/QFunctionDefinition.cpp @@ -28,15 +28,40 @@ 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..a086585cd 100644 --- a/mix/QVariableDeclaration.cpp +++ b/mix/QVariableDeclaration.cpp @@ -24,26 +24,28 @@ #include #include "CodeModel.h" +using namespace solidity; + namespace dev { namespace mix { -QVariableDeclaration::QVariableDeclaration(QObject* _parent, solidity::VariableDeclaration const* _v): - QBasicNodeDefinition(_parent, _v), - m_type(new QSolidityType(this, CodeModel::nodeType(_v->getType().get()))) +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_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_type(new QSolidityType(this, CodeModel::nodeType(_type))), m_isIndexed(_isIndexed) { } 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.qrc b/mix/qml.qrc index 784404270..16bb01b83 100644 --- a/mix/qml.qrc +++ b/mix/qml.qrc @@ -64,5 +64,10 @@ qml/js/ansi2html.js qml/js/NetworkDeployment.js qml/js/InputValidator.js + qml/Block.qml + qml/BlockChain.qml + qml/ScenarioExecution.qml + qml/ScenarioLoader.qml + qml/ScenarioButton.qml diff --git a/mix/qml/Application.qml b/mix/qml/Application.qml index d041f421e..61a2e09b1 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 } } } @@ -211,8 +209,8 @@ ApplicationWindow { 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 } @@ -225,15 +223,6 @@ ApplicationWindow { 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 text: qsTr("Show Project Navigator") diff --git a/mix/qml/Block.qml b/mix/qml/Block.qml new file mode 100644 index 000000000..6fb274ccd --- /dev/null +++ b/mix/qml/Block.qml @@ -0,0 +1,346 @@ +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 +{ + 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 + } + + 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" + } + } + } + } + + 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" + + 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 { + 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 + } + + 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 + } + + 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 "" + } + } + + 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 + } + + 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: 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 + 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 + } + } + + Text { + anchors.left: parent.left + anchors.leftMargin: horizontalMargin + id: logsText + } + } + } + } + } + } +} + diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml new file mode 100644 index 000000000..d3fad6fda --- /dev/null +++ b/mix/qml/BlockChain.qml @@ -0,0 +1,480 @@ +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 "." + +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]; + 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 9decc91ae..0129f864d 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 @@ -40,6 +39,11 @@ Rectangle { machineStates.updateHeight(); } + function setTr(tr) + { + trName.text = tr.label + } + function displayCompilationErrorIfAny() { debugScrollArea.visible = false; @@ -61,7 +65,6 @@ Rectangle { { Debugger.init(data); debugScrollArea.visible = true; - compilationErrorArea.visible = false; machineStates.visible = true; } if (giveFocus) @@ -97,96 +100,77 @@ 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 + ColumnLayout { + id: debugScrollArea + anchors.fill: parent + //orientation: Qt.Vertical + spacing: 0 + RowLayout { - width: parent.width - anchors.top: parent.top - spacing: 15 + Layout.preferredWidth: parent.width + Layout.preferredHeight: 30 Rectangle { - height: 15 - Button { - text: qsTr("Back to Debugger") - onClicked: { - debugScrollArea.visible = true; - compilationErrorArea.visible = false; - machineStates.visible = true; - } + Layout.preferredWidth: parent.width + Layout.preferredHeight: parent.height + color: "transparent" + Text { + anchors.centerIn: parent + text: qsTr("Current Transaction") } - } - RowLayout - { - height: 100 - ColumnLayout + Rectangle { - Text { - color: "red" - id: errorLocation + 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 } - Text { - color: "#4a4a4a" - id: errorDetail + MouseArea + { + anchors.fill: parent + onClicked: + { + Debugger.init(null); + panelClosed() + } } } } + } + RowLayout + { + Layout.preferredWidth: parent.width + Layout.preferredHeight: 30 Rectangle { - width: parent.width - 6 - height: 2 - color: "#d0d0d0" - } - - RowLayout - { - Text - { - color: "#4a4a4a" - id: errorLine + Layout.preferredWidth: parent.width + Layout.preferredHeight: parent.height + color: "#2C79D3" + Text { + id: trName + color: "white" + anchors.centerIn: parent } } } - } - - Splitter { - id: debugScrollArea - anchors.fill: parent - orientation: Qt.Vertical - - 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 - } ScrollView { @@ -230,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; @@ -562,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 67f45f973..de19baf35 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 @@ -43,7 +44,7 @@ Rectangle { } Connections { - target: rightView + target: debugPanel onDebugExecuteLocation: { codeEditor.highlightExecution(documentId, location); } @@ -52,7 +53,7 @@ Rectangle { 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,45 @@ Rectangle { } } - Debugger { + ScenarioExecution + { + id: scenarioExe; visible: false; - id: rightView; Layout.fillHeight: true Keys.onEscapePressed: visible = false - Layout.minimumWidth: 515 + 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 c880f0904..4781d092b 100644 --- a/mix/qml/QAddressView.qml +++ b/mix/qml/QAddressView.qml @@ -39,21 +39,26 @@ Item { accountRef.clear(); accountRef.append({"itemid": " - "}); - - if (subType === "contract" || subType === "address") + 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/ScenarioButton.qml b/mix/qml/ScenarioButton.qml new file mode 100644 index 000000000..4dd7bc53f --- /dev/null +++ b/mix/qml/ScenarioButton.qml @@ -0,0 +1,67 @@ +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 + 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 + } + + 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 new file mode 100644 index 000000000..bc872bff7 --- /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 { + color: "#ededed" + property alias bc: blockChain + + Connections + { + target: projectModel + onProjectLoaded: { + loader.init() + } + + } + + 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" + } + + 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..93f4f059b --- /dev/null +++ b/mix/qml/ScenarioLoader.qml @@ -0,0 +1,175 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Controls.Styles 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 +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") + } + } + +} diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index d3062af9e..992113cc6 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -20,13 +20,29 @@ Item { 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 - 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]))) + } + return ret; } function fromPlainAccountItem(t) @@ -58,9 +74,13 @@ Item { sender: t.sender, isContractCreation: t.isContractCreation, label: t.label, - isFunctionCall: t.isFunctionCall + isFunctionCall: t.isFunctionCall, + saveStatus: t.saveStatus }; + if (r.saveStatus === undefined) + r.saveStatus = true + if (r.isFunctionCall === undefined) r.isFunctionCall = true; @@ -76,9 +96,21 @@ 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, + blocks: s.blocks.map(toPlainBlockItem), transactions: s.transactions.map(toPlainTransactionItem), accounts: s.accounts.map(toPlainAccountItem), contracts: s.contracts.map(toPlainAccountItem), @@ -96,6 +128,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 { @@ -125,7 +168,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,6 +190,8 @@ Item { projectData.states.push(toPlainStateItem(stateList[i])); } projectData.defaultStateIndex = stateListModel.defaultStateIndex; + stateListModel.data = projectData + } onNewProject: { var state = toPlainStateItem(stateListModel.createDefaultState()); @@ -170,6 +216,11 @@ Item { id: stateDialog onAccepted: { var item = stateDialog.getItem(); + saveState(item); + } + + function saveState(item) + { if (stateDialog.stateIndex < stateListModel.count) { if (stateDialog.isDefault) stateListModel.defaultStateIndex = stateIndex; @@ -190,6 +241,7 @@ Item { ListModel { id: stateListModel property int defaultStateIndex: 0 + property variant data signal defaultStateChanged; signal stateListModelReady; signal stateRun(int index) @@ -208,12 +260,32 @@ 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 createDefaultState() { var item = { title: "", transactions: [], accounts: [], - contracts: [] + contracts: [], + blocks: [{ status: "pending", number: -1, hash: "", transactions: []}] }; var account = newAccount("1000000", QEther.Ether, defaultAccount) @@ -228,6 +300,7 @@ 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 +357,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,7 +378,7 @@ Item { function runState(index) { var item = stateList[index]; - clientModel.setupState(item); + clientModel.setupScenario(item); stateRun(index); } @@ -322,8 +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 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..880f22057 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..287ba08c2 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/img/newIcon.png b/mix/qml/img/newIcon.png new file mode 100644 index 000000000..016d0ddbb Binary files /dev/null and b/mix/qml/img/newIcon.png differ diff --git a/mix/qml/img/newIcon@2x.png b/mix/qml/img/newIcon@2x.png new file mode 100644 index 000000000..085fcb686 Binary files /dev/null and b/mix/qml/img/newIcon@2x.png differ diff --git a/mix/qml/js/ProjectModel.js b/mix/qml/js/ProjectModel.js index 6fce7686d..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,50 +98,52 @@ function saveProjectFile() function loadProject(path) { closeProject(function() { - console.log("Loading project at " + path); - var projectFile = path + projectFileName; - var json = fileIo.readFile(projectFile); - 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); }); } @@ -160,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 b9a011b66..f8bad03ed 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 }; } diff --git a/mix/res.qrc b/mix/res.qrc index ac0af57ac..b50aa3d9f 100644 --- a/mix/res.qrc +++ b/mix/res.qrc @@ -68,5 +68,27 @@ qml/img/warningicon.png qml/img/warningicon@2x.png qml/QAddressView.qml + 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 diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index f7da0238e..733ccb6d0 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -344,6 +344,18 @@ void ImportTest::exportTest(bytes const& _output, State const& _statePost) m_TestObject["out"] = (_output.size() > 4096 && !Options::get().fulloutput) ? "#" + toString(_output.size()) : toHex(_output, 2, HexPrefix::Add); + // compare expected output with post output + if (m_TestObject.count("expectOut") > 0) + { + std::string warning = "Check State: Error! Unexpected output: " + m_TestObject["out"].get_str() + " Expected: " + m_TestObject["expectOut"].get_str(); + if (Options::get().checkState) + 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 m_TestObject["logs"] = exportLog(_statePost.pending().size() ? _statePost.log(0) : LogEntries()); diff --git a/test/libethereum/StateTestsFiller/stPreCompiledContractsFiller.json b/test/libethereum/StateTestsFiller/stPreCompiledContractsFiller.json index 1c870c543..8781e5271 100644 --- a/test/libethereum/StateTestsFiller/stPreCompiledContractsFiller.json +++ b/test/libethereum/StateTestsFiller/stPreCompiledContractsFiller.json @@ -3644,6 +3644,5 @@ "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", "data" : "" } - }, -} - + } +} \ No newline at end of file diff --git a/test/libethereum/StateTestsFiller/stPrecompiledContractsTransactionFiller.json b/test/libethereum/StateTestsFiller/stPrecompiledContractsTransactionFiller.json new file mode 100644 index 000000000..ff1e8c5d1 --- /dev/null +++ b/test/libethereum/StateTestsFiller/stPrecompiledContractsTransactionFiller.json @@ -0,0 +1,854 @@ +{ + "CallEcrecover0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "300000", + "to" : "0000000000000000000000000000000000000001", + "value" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c000000000000000000000000000000000000000000000000000000000000001c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549" + } + }, + + "CallEcrecover80": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x0000000000000000000000003f17f1962b36e491b30a40b2405849e597ba5fb5", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "300000", + "to" : "0000000000000000000000000000000000000001", + "value" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "00c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c000000000000000000000000000000000000000000000000000000000000001c00b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f00b940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549" + } + }, + + "CallEcrecover0_gas3000": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "3000", + "to" : "0000000000000000000000000000000000000001", + "value" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c000000000000000000000000000000000000000000000000000000000000001c73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549" + } + }, + + "CallEcrecover0_0input": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "300000", + "to" : "0000000000000000000000000000000000000001", + "value" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallEcrecover1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "300000", + "to" : "0000000000000000000000000000000000000001", + "value" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c000000000000000000000000000000000000000000000000000000000000000173b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549" + } + }, + + "CallEcrecover2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x0000000000000000000000000000000000000000000000000000000000000000", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "300000", + "to" : "0000000000000000000000000000000000000001", + "value" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c0073b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75feeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549" + } + }, + + "CallEcrecover3": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x000000000000000000000000e4319f4b631c6d0fcfc84045dbcb676865fe5e13", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "300000", + "to" : "0000000000000000000000000000000000000001", + "value" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "2f380a2dea7e778d81affc2443403b8fe4644db442ae4862ff5bb3732829cdb9000000000000000000000000000000000000000000000000000000000000001b6b65ccb0558806e9b097f27a396d08f964e37b8b7af6ceeb516ff86739fbea0a37cbc8d883e129a4b1ef9d5f1df53c4f21a3ef147cf2a50a4ede0eb06ce092d4" + } + }, + + "CallSha256_0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0xec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "300000", + "to" : "0000000000000000000000000000000000000002", + "value" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "000000000000000000000000000000000000000000000000000000000000001" + } + }, + + "CallSha256_2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "300000", + "to" : "0000000000000000000000000000000000000002", + "value" : "0", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallSha256_1_nonzeroValue": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "200000", + "to" : "0000000000000000000000000000000000000002", + "value" : "0x13", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallSha256_2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0xcb39b3bde22925b2f931111130c774761d8895e0e08437c9b396c1e97d10f34d", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "200000", + "to" : "0000000000000000000000000000000000000002", + "value" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "0000000000000000000000000000000000000000000000000000000000000000f34578907f" + } + }, + + "CallSha256_3": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x7392925565d67be8e9620aacbcfaecd8cb6ec58d709d25da9eccf1d08a41ce35", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "200000", + "to" : "0000000000000000000000000000000000000002", + "value" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "000000000000000000000000000000000000000000000000000000f34578907f0000000000" + } + }, + + "CallSha256_4": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0xaf9613760f72635fbdb44a5a0a63c39f12af30f950a6ee5c971be188e89c4051", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "200000", + "to" : "0000000000000000000000000000000000000002", + "value" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + } + }, + + "CallSha256_5": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x259911ec9f4b02b7975dfa3f5da78fc58b7066604bdaea66c4485c90f6f55bec", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "200000", + "to" : "0000000000000000000000000000000000000002", + "value" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + + "CallRipemd160_0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x000000000000000000000000ae387fcfeb723c3f5964509af111cf5a67f30661", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "200000", + "to" : "0000000000000000000000000000000000000003", + "value" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "000000000000000000000000000000000000000000000000000000000000001" + } + }, + + "CallRipemd160_1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "200000", + "to" : "0000000000000000000000000000000000000003", + "value" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallRipemd160_2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x000000000000000000000000dbc100f916bfbc53535573d98cf0cbb3a5b36124", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "200000", + "to" : "0000000000000000000000000000000000000003", + "value" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "0000000000000000000000000000000000000000000000000000000000000000f34578907f" + } + }, + + "CallRipemd160_3": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x000000000000000000000000316750573f9be26bc17727b47cacedbd0ab3e6ca", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "200000", + "to" : "0000000000000000000000000000000000000003", + "value" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "000000000000000000000000000000000000000000000000000000f34578907f0000000000" + } + }, + + "CallRipemd160_4": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x0000000000000000000000001cf4e77f5966e13e109703cd8a0df7ceda7f3dc3", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "200000", + "to" : "0000000000000000000000000000000000000003", + "value" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + } + }, + + "CallRipemd160_5": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "200000", + "to" : "0000000000000000000000000000000000000003", + "value" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + + "CallIdentitiy_0": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x0000000000000000000000000000000000000000000000000000000000000001", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "200000", + "to" : "0000000000000000000000000000000000000004", + "value" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "000000000000000000000000000000000000000000000000000000000000001" + } + }, + + "CallIdentitiy_1": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "200000", + "to" : "0000000000000000000000000000000000000004", + "value" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallIdentitiy_1_nonzeroValue": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "200000", + "to" : "0000000000000000000000000000000000000004", + "value" : "0x13", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + + "CallIdentitiy_2": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x0000000000000000000000000000000000000000000000000000000000000000f34578907f", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "200000", + "to" : "0000000000000000000000000000000000000004", + "value" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "0000000000000000000000000000000000000000000000000000000000000000f34578907f" + } + }, + + "CallIdentitiy_3": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x000000000000000000000000000000000000000000000000000000f34578907f0000000000", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "200000", + "to" : "0000000000000000000000000000000000000004", + "value" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "000000000000000000000000000000000000000000000000000000f34578907f0000000000" + } + }, + + "CallIdentitiy_4": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "200000", + "to" : "0000000000000000000000000000000000000004", + "value" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + } + }, + + "CallIdentitiy_4_gas17": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "0x", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "23176", + "to" : "0000000000000000000000000000000000000004", + "value" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + } + }, + + "CallIdentitiy_5": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba" + }, + "expectOut" : "#35659", + "pre" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "200000", + "to" : "0000000000000000000000000000000000000004", + "value" : "", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + + "callTxToPrecompiled_1": { + "env": { + "currentCoinbase": "aa69d40e4ab383b25fa6c17560dd77b387480dd8", + "currentDifficulty": "0x0100", + "currentGasLimit": "0x0f4240", + "currentNumber": "0x00", + "currentTimestamp": "0x01", + "previousHash": "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6" + }, + "expectOut": "0x0000000000000000000000000000000000000000000000000000000000000000", + "pre": { + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": { + "balance": "150000240000000000000000", + "code": "0x", + "nonce": "0x31", + "storage": {} + }, + "aa69d40e4ab383b25fa6c17560dd77b387480dd8": { + "balance": "0x", + "code": "0x", + "nonce": "0x00", + "storage": {} + }, + "0000000000000000000000000000000000000001": { + "balance": "0x1", + "code": "0x", + "nonce": "0x00", + "storage": {} + } + }, + "transaction": { + "data": "", + "gasLimit": "0x09965e", + "gasPrice": "0x09184e72a000", + "nonce": "0x31", + "secretKey": "c85ef7d79691fe79573b1a7064c19c1a9819ebdbd1faaab1a8ec92344438aaf4", + "to": "0000000000000000000000000000000000000001", + "value": "0x0a968163f0a57b400000" + } + } +} diff --git a/test/libethereum/state.cpp b/test/libethereum/state.cpp index ed5cf14ac..5eb3c76c3 100644 --- a/test/libethereum/state.cpp +++ b/test/libethereum/state.cpp @@ -129,6 +129,11 @@ BOOST_AUTO_TEST_CASE(stPreCompiledContracts) dev::test::executeTests("stPreCompiledContracts", "/StateTests",dev::test::getFolder(__FILE__) + "/StateTestsFiller", dev::test::doStateTests); } +BOOST_AUTO_TEST_CASE(stPrecompiledContractsTransaction) +{ + dev::test::executeTests("stPrecompiledContractsTransaction", "/StateTests",dev::test::getFolder(__FILE__) + "/StateTestsFiller", dev::test::doStateTests); +} + BOOST_AUTO_TEST_CASE(stLogTests) { dev::test::executeTests("stLogTests", "/StateTests",dev::test::getFolder(__FILE__) + "/StateTestsFiller", dev::test::doStateTests); diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index d52c650f9..5bbab2e1c 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -33,7 +33,7 @@ using namespace dev::eth; using namespace dev::test; FakeExtVM::FakeExtVM(eth::BlockInfo const& _previousBlock, eth::BlockInfo const& _currentBlock, unsigned _depth): /// TODO: XXX: remove the default argument & fix. - ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number), _depth) {} + ExtVMFace(Address(), Address(), Address(), 0, 1, bytesConstRef(), bytes(), EmptySHA3, _previousBlock, _currentBlock, test::lastHashes(_currentBlock.number), _depth) {} h160 FakeExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _init, OnOpFunc const&) { @@ -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); } diff --git a/test/libsolidity/Assembly.cpp b/test/libsolidity/Assembly.cpp index ccc4bf811..fd4bbcf6d 100644 --- a/test/libsolidity/Assembly.cpp +++ b/test/libsolidity/Assembly.cpp @@ -105,8 +105,8 @@ BOOST_AUTO_TEST_CASE(location_test) shared_ptr n = make_shared("source"); AssemblyItems items = compileContract(sourceCode); vector locations = - vector(11, SourceLocation(2, 75, n)) + - vector(12, SourceLocation(20, 72, n)) + + vector(17, SourceLocation(2, 75, n)) + + vector(14, SourceLocation(20, 72, n)) + vector{SourceLocation(42, 51, n), SourceLocation(65, 67, n)} + vector(4, SourceLocation(58, 67, n)) + vector(3, SourceLocation(20, 72, n)); diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 89ed81e23..f12abd48e 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -566,16 +566,16 @@ BOOST_AUTO_TEST_CASE(strings) BOOST_AUTO_TEST_CASE(empty_string_on_stack) { - char const* sourceCode = "contract test {\n" - " function run(bytes0 empty, uint8 inp) returns(uint16 a, bytes0 b, bytes4 c) {\n" - " var x = \"abc\";\n" - " var y = \"\";\n" - " var z = inp;\n" - " a = z; b = y; c = x;" - " }\n" - "}\n"; + char const* sourceCode = R"( + contract test { + function run() external returns(bytes2 ret) { + var y = ""; + ret = y; + } + } + )"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("run(bytes0,uint8)", string(), byte(0x02)) == encodeArgs(0x2, string(""), string("abc\0"))); + BOOST_CHECK(callContractFunction("run()") == encodeArgs(byte(0x00))); } BOOST_AUTO_TEST_CASE(inc_dec_operators) @@ -2396,7 +2396,7 @@ BOOST_AUTO_TEST_CASE(event_really_lots_of_data) callContractFunction("deposit()"); BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); - BOOST_CHECK(m_logs[0].data == encodeArgs(10, 4, 15) + FixedHash<4>(dev::sha3("deposit()")).asBytes()); + BOOST_CHECK(m_logs[0].data == encodeArgs(10, 0x60, 15, 4) + FixedHash<4>(dev::sha3("deposit()")).asBytes()); BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(uint256,bytes,uint256)"))); } @@ -2420,7 +2420,7 @@ BOOST_AUTO_TEST_CASE(event_really_lots_of_data_from_storage) callContractFunction("deposit()"); BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); - BOOST_CHECK(m_logs[0].data == encodeArgs(10, 3, 15) + asBytes("ABC")); + BOOST_CHECK(m_logs[0].data == encodeArgs(10, 0x60, 15, 3) + asBytes("ABC")); BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(uint256,bytes,uint256)"))); } @@ -2531,6 +2531,27 @@ BOOST_AUTO_TEST_CASE(sha3_with_bytes) BOOST_CHECK(callContractFunction("foo()") == encodeArgs(true)); } +BOOST_AUTO_TEST_CASE(iterated_sha3_with_bytes) +{ + char const* sourceCode = R"( + contract c { + bytes data; + function foo() returns (bytes32) + { + data.length = 3; + data[0] = "x"; + data[1] = "y"; + data[2] = "z"; + return sha3("b", sha3(data), "a"); + } + } + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("foo()") == encodeArgs( + u256(dev::sha3(bytes{'b'} + dev::sha3("xyz").asBytes() + bytes{'a'})) + )); +} + BOOST_AUTO_TEST_CASE(generic_call) { char const* sourceCode = R"**( @@ -3786,30 +3807,6 @@ BOOST_AUTO_TEST_CASE(packed_storage_structs_delete) BOOST_CHECK(m_state.storage(m_contractAddress).empty()); } -BOOST_AUTO_TEST_CASE(packed_storage_structs_with_bytes0) -{ - char const* sourceCode = R"( - contract C { - struct str { uint8 a; bytes0 b; uint8 c; } - uint8 a; - bytes0 x; - uint8 b; - str data; - function test() returns (bool) { - a = 2; - b = 3; - data.a = 4; - data.c = 5; - delete x; - delete data.b; - return a == 2 && b == 3 && data.a == 4 && data.c == 5; - } - } - )"; - compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("test()") == encodeArgs(true)); -} - BOOST_AUTO_TEST_CASE(overloaded_function_call_resolve_to_first) { char const* sourceCode = R"( @@ -4209,6 +4206,32 @@ BOOST_AUTO_TEST_CASE(failing_send) BOOST_REQUIRE(callContractFunction("callHelper(address)", c_helperAddress) == encodeArgs(true, 20)); } +BOOST_AUTO_TEST_CASE(reusing_memory) +{ + // Invoke some features that use memory and test that they do not interfere with each other. + char const* sourceCode = R"( + contract Helper { + uint public flag; + function Helper(uint x) { + flag = x; + } + } + contract Main { + mapping(uint => uint) map; + function f(uint x) returns (uint) { + map[x] = x; + return (new Helper(uint(sha3(this.g(map[x]))))).flag(); + } + function g(uint a) returns (uint) + { + return map[a]; + } + } + )"; + compileAndRun(sourceCode, 0, "Main"); + BOOST_REQUIRE(callContractFunction("f(uint256)", 0x34) == encodeArgs(dev::sha3(dev::toBigEndian(u256(0x34))))); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 73bbcb162..3948a4a23 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -558,16 +558,6 @@ BOOST_AUTO_TEST_CASE(function_external_call_not_allowed_conversion) BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); } -// todo delete when implemented -BOOST_AUTO_TEST_CASE(arrays_in_internal_functions) -{ - char const* text = R"( - contract Test { - function foo(address[] addresses) {} - })"; - BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); -} - BOOST_AUTO_TEST_CASE(function_internal_allowed_conversion) { char const* text = R"( @@ -1579,7 +1569,6 @@ BOOST_AUTO_TEST_CASE(test_fromElementaryTypeName) BOOST_CHECK(*Type::fromElementaryTypeName(Token::UInt256) == *make_shared(256, IntegerType::Modifier::Unsigned)); BOOST_CHECK(*Type::fromElementaryTypeName(Token::Byte) == *make_shared(1)); - BOOST_CHECK(*Type::fromElementaryTypeName(Token::Bytes0) == *make_shared(0)); BOOST_CHECK(*Type::fromElementaryTypeName(Token::Bytes1) == *make_shared(1)); BOOST_CHECK(*Type::fromElementaryTypeName(Token::Bytes2) == *make_shared(2)); BOOST_CHECK(*Type::fromElementaryTypeName(Token::Bytes3) == *make_shared(3)); @@ -1666,16 +1655,6 @@ BOOST_AUTO_TEST_CASE(local_const_variable) BOOST_CHECK_THROW(parseTextAndResolveNames(text), ParserError); } -BOOST_AUTO_TEST_CASE(bytes0_array) -{ - char const* text = R"( - contract Foo { - bytes0[] illegalArray; - } - )"; - BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); -} - BOOST_AUTO_TEST_CASE(overloaded_function_cannot_resolve) { char const* sourceCode = R"( 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 diff --git a/test/libsolidity/SolidityWallet.cpp b/test/libsolidity/SolidityWallet.cpp new file mode 100644 index 000000000..09820b87b --- /dev/null +++ b/test/libsolidity/SolidityWallet.cpp @@ -0,0 +1,491 @@ +/* + 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 . +*/ +/** + * @author Christian + * @date 2015 + * Tests for a (comparatively) complex multisig wallet contract. + */ + +#include +#include +#include +#include +#include + +using namespace std; + +namespace dev +{ +namespace solidity +{ +namespace test +{ + +static char const* walletCode = R"DELIMITER( +//sol Wallet +// Multi-sig, daily-limited account proxy/wallet. +// @authors: +// Gav Wood +// inheritable "property" contract that enables methods to be protected by requiring the acquiescence of either a +// single, or, crucially, each of a number of, designated owners. +// usage: +// use modifiers onlyowner (just own owned) or onlymanyowners(hash), whereby the same hash must be provided by +// some number (specified in constructor) of the set of owners (specified in the constructor, modifiable) before the +// interior is executed. +contract multiowned { + // struct for the status of a pending operation. + struct PendingState { + uint yetNeeded; + uint ownersDone; + uint index; + } + // this contract only has five types of events: it can accept a confirmation, in which case + // we record owner and operation (hash) alongside it. + event Confirmation(address owner, bytes32 operation); + event Revoke(address owner, bytes32 operation); + // some others are in the case of an owner changing. + event OwnerChanged(address oldOwner, address newOwner); + event OwnerAdded(address newOwner); + event OwnerRemoved(address oldOwner); + // the last one is emitted if the required signatures change + event RequirementChanged(uint newRequirement); + // constructor is given number of sigs required to do protected "onlymanyowners" transactions + // as well as the selection of addresses capable of confirming them. + function multiowned() { + m_required = 1; + m_numOwners = 1; + m_owners[m_numOwners] = uint(msg.sender); + m_ownerIndex[uint(msg.sender)] = m_numOwners; + } + // simple single-sig function modifier. + modifier onlyowner { + if (isOwner(msg.sender)) + _ + } + // multi-sig function modifier: the operation must have an intrinsic hash in order + // that later attempts can be realised as the same underlying operation and + // thus count as confirmations. + modifier onlymanyowners(bytes32 _operation) { + if (confirmed(_operation)) + _ + } + // Revokes a prior confirmation of the given operation + function revoke(bytes32 _operation) external { + uint ownerIndex = m_ownerIndex[uint(msg.sender)]; + // make sure they're an owner + if (ownerIndex == 0) return; + uint ownerIndexBit = 2**ownerIndex; + var pending = m_pending[_operation]; + if (pending.ownersDone & ownerIndexBit > 0) { + pending.yetNeeded++; + pending.ownersDone -= ownerIndexBit; + Revoke(msg.sender, _operation); + } + } + function confirmed(bytes32 _operation) internal returns (bool) { + // determine what index the present sender is: + uint ownerIndex = m_ownerIndex[uint(msg.sender)]; + // make sure they're an owner + if (ownerIndex == 0) return; + + var pending = m_pending[_operation]; + // if we're not yet working on this operation, switch over and reset the confirmation status. + if (pending.yetNeeded == 0) { + // reset count of confirmations needed. + pending.yetNeeded = m_required; + // reset which owners have confirmed (none) - set our bitmap to 0. + pending.ownersDone = 0; + pending.index = m_pendingIndex.length++; + m_pendingIndex[pending.index] = _operation; + } + // determine the bit to set for this owner. + uint ownerIndexBit = 2**ownerIndex; + // make sure we (the message sender) haven't confirmed this operation previously. + if (pending.ownersDone & ownerIndexBit == 0) { + Confirmation(msg.sender, _operation); + // ok - check if count is enough to go ahead. + if (pending.yetNeeded <= 1) { + // enough confirmations: reset and run interior. + delete m_pendingIndex[m_pending[_operation].index]; + delete m_pending[_operation]; + return true; + } + else + { + // not enough: record that this owner in particular confirmed. + pending.yetNeeded--; + pending.ownersDone |= ownerIndexBit; + } + } + } + // Replaces an owner `_from` with another `_to`. + function changeOwner(address _from, address _to) onlymanyowners(sha3(msg.data)) external { + if (isOwner(_to)) return; + uint ownerIndex = m_ownerIndex[uint(_from)]; + if (ownerIndex == 0) return; + + clearPending(); + m_owners[ownerIndex] = uint(_to); + m_ownerIndex[uint(_from)] = 0; + m_ownerIndex[uint(_to)] = ownerIndex; + OwnerChanged(_from, _to); + } + function addOwner(address _owner) onlymanyowners(sha3(msg.data)) external { + if (isOwner(_owner)) return; + + clearPending(); + if (m_numOwners >= c_maxOwners) + reorganizeOwners(); + if (m_numOwners >= c_maxOwners) + return; + m_numOwners++; + m_owners[m_numOwners] = uint(_owner); + m_ownerIndex[uint(_owner)] = m_numOwners; + OwnerAdded(_owner); + } + function removeOwner(address _owner) onlymanyowners(sha3(msg.data)) external { + uint ownerIndex = m_ownerIndex[uint(_owner)]; + if (ownerIndex == 0) return; + if (m_required > m_numOwners - 1) return; + + m_owners[ownerIndex] = 0; + m_ownerIndex[uint(_owner)] = 0; + clearPending(); + reorganizeOwners(); //make sure m_numOwner is equal to the number of owners and always points to the optimal free slot + OwnerRemoved(_owner); + } + function reorganizeOwners() private returns (bool) { + uint free = 1; + while (free < m_numOwners) + { + while (free < m_numOwners && m_owners[free] != 0) free++; + while (m_numOwners > 1 && m_owners[m_numOwners] == 0) m_numOwners--; + if (free < m_numOwners && m_owners[m_numOwners] != 0 && m_owners[free] == 0) + { + m_owners[free] = m_owners[m_numOwners]; + m_ownerIndex[m_owners[free]] = free; + m_owners[m_numOwners] = 0; + } + } + } + function clearPending() internal { + uint length = m_pendingIndex.length; + for (uint i = 0; i < length; ++i) + if (m_pendingIndex[i] != 0) + delete m_pending[m_pendingIndex[i]]; + delete m_pendingIndex; + } + function changeRequirement(uint _newRequired) onlymanyowners(sha3(msg.data)) external { + if (_newRequired > m_numOwners) return; + m_required = _newRequired; + clearPending(); + RequirementChanged(_newRequired); + } + function isOwner(address _addr) returns (bool) { + return m_ownerIndex[uint(_addr)] > 0; + } + + // the number of owners that must confirm the same operation before it is run. + uint m_required; + // pointer used to find a free slot in m_owners + uint m_numOwners; + // list of owners + uint[256] m_owners; + uint constant c_maxOwners = 250; + // index on the list of owners to allow reverse lookup + mapping(uint => uint) m_ownerIndex; + // the ongoing operations. + mapping(bytes32 => PendingState) m_pending; + bytes32[] m_pendingIndex; +} + +// inheritable "property" contract that enables methods to be protected by placing a linear limit (specifiable) +// on a particular resource per calendar day. is multiowned to allow the limit to be altered. resource that method +// uses is specified in the modifier. +contract daylimit is multiowned { + // constructor - just records the present day's index. + function daylimit() { + m_lastDay = today(); + } + // (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today. + function setDailyLimit(uint _newLimit) onlymanyowners(sha3(msg.data)) external { + m_dailyLimit = _newLimit; + } + // (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today. + function resetSpentToday() onlymanyowners(sha3(msg.data)) external { + m_spentToday = 0; + } + // checks to see if there is at least `_value` left from the daily limit today. if there is, subtracts it and + // returns true. otherwise just returns false. + function underLimit(uint _value) internal onlyowner returns (bool) { + // reset the spend limit if we're on a different day to last time. + if (today() > m_lastDay) { + m_spentToday = 0; + m_lastDay = today(); + } + // check to see if there's enough left - if so, subtract and return true. + if (m_spentToday + _value >= m_spentToday && m_spentToday + _value <= m_dailyLimit) { + m_spentToday += _value; + return true; + } + return false; + } + // simple modifier for daily limit. + modifier limitedDaily(uint _value) { + if (underLimit(_value)) + _ + } + // determines today's index. + function today() private constant returns (uint) { return now / 1 days; } + uint m_spentToday; + uint m_dailyLimit; + uint m_lastDay; +} +// interface contract for multisig proxy contracts; see below for docs. +contract multisig { + event Deposit(address from, uint value); + event SingleTransact(address owner, uint value, address to, bytes data); + event MultiTransact(address owner, bytes32 operation, uint value, address to, bytes data); + event ConfirmationNeeded(bytes32 operation, address initiator, uint value, address to, bytes data); + function changeOwner(address _from, address _to) external; + function execute(address _to, uint _value, bytes _data) external returns (bytes32); + function confirm(bytes32 _h) returns (bool); +} +// usage: +// bytes32 h = Wallet(w).from(oneOwner).transact(to, value, data); +// Wallet(w).from(anotherOwner).confirm(h); +contract Wallet is multisig, multiowned, daylimit { + // Transaction structure to remember details of transaction lest it need be saved for a later call. + struct Transaction { + address to; + uint value; + bytes data; + } + // logged events: + // Funds has arrived into the wallet (record how much). + event Deposit(address from, uint value); + // Single transaction going out of the wallet (record who signed for it, how much, and to whom it's going). + event SingleTransact(address owner, uint value, address to, bytes data); + // constructor - just pass on the owner arra to the multiowned. + event Created(); + function Wallet() { + Created(); + } + // kills the contract sending everything to `_to`. + function kill(address _to) onlymanyowners(sha3(msg.data)) external { + suicide(_to); + } + // gets called when no other function matches + function() { + // just being sent some cash? + if (msg.value > 0) + Deposit(msg.sender, msg.value); + } + // Outside-visible transact entry point. Executes transacion immediately if below daily spend limit. + // If not, goes into multisig process. We provide a hash on return to allow the sender to provide + // shortcuts for the other confirmations (allowing them to avoid replicating the _to, _value + // and _data arguments). They still get the option of using them if they want, anyways. + function execute(address _to, uint _value, bytes _data) onlyowner external returns (bytes32 _r) { + // first, take the opportunity to check that we're under the daily limit. + if (underLimit(_value)) { + SingleTransact(msg.sender, _value, _to, _data); + // yes - just execute the call. + _to.call.value(_value)(_data); + return 0; + } + // determine our operation hash. + _r = sha3(msg.data); + if (!confirm(_r) && m_txs[_r].to == 0) { + m_txs[_r].to = _to; + m_txs[_r].value = _value; + m_txs[_r].data = _data; + ConfirmationNeeded(_r, msg.sender, _value, _to, _data); + } + } + // confirm a transaction through just the hash. we use the previous transactions map, m_txs, in order + // to determine the body of the transaction from the hash provided. + function confirm(bytes32 _h) onlymanyowners(_h) returns (bool) { + if (m_txs[_h].to != 0) { + m_txs[_h].to.call.value(m_txs[_h].value)(m_txs[_h].data); + MultiTransact(msg.sender, _h, m_txs[_h].value, m_txs[_h].to, m_txs[_h].data); + delete m_txs[_h]; + return true; + } + } + function clearPending() internal { + uint length = m_pendingIndex.length; + for (uint i = 0; i < length; ++i) + delete m_txs[m_pendingIndex[i]]; + super.clearPending(); + } + // pending transactions we have at present. + mapping (bytes32 => Transaction) m_txs; +} +)DELIMITER"; + +static unique_ptr s_compiledWallet; + +class WalletTestFramework: public ExecutionFramework +{ +protected: + void deployWallet(u256 const& _value = 0) + { + if (!s_compiledWallet) + { + m_optimize = true; + m_compiler.reset(false, m_addStandardSources); + m_compiler.addSource("", walletCode); + ETH_TEST_REQUIRE_NO_THROW(m_compiler.compile(m_optimize, m_optimizeRuns), "Compiling contract failed"); + s_compiledWallet.reset(new bytes(m_compiler.getBytecode("Wallet"))); + } + sendMessage(*s_compiledWallet, true, _value); + BOOST_REQUIRE(!m_output.empty()); + } +}; + +/// This is a test suite that tests optimised code! +BOOST_FIXTURE_TEST_SUITE(SolidityWallet, WalletTestFramework) + +BOOST_AUTO_TEST_CASE(creation) +{ + deployWallet(200); + BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(m_sender, h256::AlignRight)) == encodeArgs(true)); + BOOST_REQUIRE(callContractFunction("isOwner(address)", ~h256(m_sender, h256::AlignRight)) == encodeArgs(false)); +} + +BOOST_AUTO_TEST_CASE(add_owners) +{ + deployWallet(200); + Address originalOwner = m_sender; + BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12)) == encodeArgs()); + BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x12)) == encodeArgs(true)); + // now let the new owner add someone + m_sender = Address(0x12); + BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x13)) == encodeArgs()); + BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x13)) == encodeArgs(true)); + // and check that a non-owner cannot add a new owner + m_sender = Address(0x50); + BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x20)) == encodeArgs()); + BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x20)) == encodeArgs(false)); + // finally check that all the owners are there + BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(originalOwner, h256::AlignRight)) == encodeArgs(true)); + BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x12)) == encodeArgs(true)); + BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x13)) == encodeArgs(true)); +} + +BOOST_AUTO_TEST_CASE(change_owners) +{ + deployWallet(200); + BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12)) == encodeArgs()); + BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x12)) == encodeArgs(true)); + BOOST_REQUIRE(callContractFunction("changeOwner(address,address)", h256(0x12), h256(0x13)) == encodeArgs()); + BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x12)) == encodeArgs(false)); + BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x13)) == encodeArgs(true)); +} + +BOOST_AUTO_TEST_CASE(remove_owner) +{ + deployWallet(200); + // add 10 owners + for (unsigned i = 0; i < 10; ++i) + { + BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12 + i)) == encodeArgs()); + BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x12 + i)) == encodeArgs(true)); + } + // check they are there again + for (unsigned i = 0; i < 10; ++i) + BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x12 + i)) == encodeArgs(true)); + // remove the odd owners + for (unsigned i = 0; i < 10; ++i) + if (i % 2 == 1) + BOOST_REQUIRE(callContractFunction("removeOwner(address)", h256(0x12 + i)) == encodeArgs()); + // check the result + for (unsigned i = 0; i < 10; ++i) + BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x12 + i)) == encodeArgs(i % 2 == 0)); + // add them again + for (unsigned i = 0; i < 10; ++i) + if (i % 2 == 1) + BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12 + i)) == encodeArgs()); + // check everyone is there + for (unsigned i = 0; i < 10; ++i) + BOOST_REQUIRE(callContractFunction("isOwner(address)", h256(0x12 + i)) == encodeArgs(true)); +} + +BOOST_AUTO_TEST_CASE(multisig_value_transfer) +{ + deployWallet(200); + BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12)) == encodeArgs()); + BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x13)) == encodeArgs()); + BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x14)) == encodeArgs()); + // 4 owners, set required to 3 + BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs()); + // check that balance is and stays zero at destination address + h256 opHash("f916231db11c12e0142dc51f23632bc655de87c63f83fc928c443e90f7aa364a"); + BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0); + m_sender = Address(0x12); + BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash)); + BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0); + m_sender = Address(0x13); + BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash)); + BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0); + m_sender = Address(0x14); + BOOST_REQUIRE(callContractFunction("execute(address,uint256,bytes)", h256(0x05), 100, 0x60, 0x00) == encodeArgs(opHash)); + // now it should go through + BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 100); +} + +BOOST_AUTO_TEST_CASE(daylimit) +{ + deployWallet(200); + BOOST_REQUIRE(callContractFunction("setDailyLimit(uint256)", h256(100)) == encodeArgs()); + BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x12)) == encodeArgs()); + BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x13)) == encodeArgs()); + BOOST_REQUIRE(callContractFunction("addOwner(address)", h256(0x14)) == encodeArgs()); + // 4 owners, set required to 3 + BOOST_REQUIRE(callContractFunction("changeRequirement(uint256)", u256(3)) == encodeArgs()); + + // try to send tx over daylimit + BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0); + m_sender = Address(0x12); + BOOST_REQUIRE( + callContractFunction("execute(address,uint256,bytes)", h256(0x05), 150, 0x60, 0x00) != + encodeArgs(u256(0)) + ); + BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0); + // try to send tx under daylimit by stranger + m_sender = Address(0x77); + BOOST_REQUIRE( + callContractFunction("execute(address,uint256,bytes)", h256(0x05), 90, 0x60, 0x00) == + encodeArgs(u256(0)) + ); + BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 0); + // now send below limit by owner + m_sender = Address(0x12); + BOOST_REQUIRE( + callContractFunction("execute(address,uint256,bytes)", h256(0x05), 90, 0x60, 0x00) == + encodeArgs(u256(0)) + ); + BOOST_CHECK_EQUAL(m_state.balance(Address(0x05)), 90); +} + +//@todo test data calls + +BOOST_AUTO_TEST_SUITE_END() + +} +} +} // end namespaces diff --git a/test/libweb3jsonrpc/webthreestubclient.h b/test/libweb3jsonrpc/webthreestubclient.h index 99fe48034..5c74e5a46 100644 --- a/test/libweb3jsonrpc/webthreestubclient.h +++ b/test/libweb3jsonrpc/webthreestubclient.h @@ -354,13 +354,13 @@ class WebThreeStubClient : public jsonrpc::Client else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } - std::string eth_compileSolidity(const std::string& param1) throw (jsonrpc::JsonRpcException) + Json::Value eth_compileSolidity(const std::string& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; p.append(param1); Json::Value result = this->CallMethod("eth_compileSolidity",p); - if (result.isString()) - return result.asString(); + if (result.isObject()) + return result; else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } @@ -374,6 +374,16 @@ class WebThreeStubClient : public jsonrpc::Client else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } + std::string eth_newFilterEx(const Json::Value& param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("eth_newFilterEx",p); + if (result.isString()) + return result.asString(); + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } std::string eth_newBlockFilter() throw (jsonrpc::JsonRpcException) { Json::Value p; @@ -414,6 +424,16 @@ class WebThreeStubClient : public jsonrpc::Client else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } + Json::Value eth_getFilterChangesEx(const std::string& param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("eth_getFilterChangesEx",p); + if (result.isArray()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } Json::Value eth_getFilterLogs(const std::string& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; @@ -424,6 +444,16 @@ class WebThreeStubClient : public jsonrpc::Client else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } + Json::Value eth_getFilterLogsEx(const std::string& param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("eth_getFilterLogsEx",p); + if (result.isArray()) + return result; + else + throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); + } Json::Value eth_getLogs(const Json::Value& param1) throw (jsonrpc::JsonRpcException) { Json::Value p; @@ -516,6 +546,16 @@ class WebThreeStubClient : public jsonrpc::Client else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } + bool eth_notePassword(const std::string& param1) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + Json::Value result = this->CallMethod("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; @@ -631,6 +671,243 @@ class WebThreeStubClient : public jsonrpc::Client else throw jsonrpc::JsonRpcException(jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString()); } + bool admin_web3_setVerbosity(int param1, const std::string& param2) throw (jsonrpc::JsonRpcException) + { + Json::Value p; + p.append(param1); + p.append(param2); + Json::Value result = this->CallMethod("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; + p.append(param1); + Json::Value result = this->CallMethod("admin_eth_blockQueueStatus",p); + if (result.isObject()) + return result; + 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_ diff --git a/third/MainWin.cpp b/third/MainWin.cpp index 3cfc016e3..f2a90cc0b 100644 --- a/third/MainWin.cpp +++ b/third/MainWin.cpp @@ -100,7 +100,7 @@ Main::Main(QWidget *parent) : setWindowFlags(Qt::Window); ui->setupUi(this); - cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; + cerr << "State root: " << CanonBlockChain::genesis().stateRoot << endl; auto gb = CanonBlockChain::createGenesisBlock(); cerr << "Block Hash: " << sha3(gb) << endl; cerr << "Block RLP: " << RLP(gb) << endl;