diff --git a/CMakeLists.txt b/CMakeLists.txt index 904badcf2..7e3b6a53c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ option(JSONRPC "Build with jsonprc. default on" ON) option(FATDB "Build with ability to list entries in the Trie. Doubles DB size, slows everything down, but good for looking at state diffs and trie contents." OFF) option(USENPM "Use npm to recompile ethereum.js if it was changed" OFF) option(PROFILING "Build in support for profiling" OFF) - +option(ROCKSDB "Use rocksdb rather than leveldb" OFF) set(BUNDLE "none" CACHE STRING "Predefined bundle of software to build (none, full, user, tests, minimal).") option(MINER "Build the CLI miner component" ON) @@ -84,7 +84,10 @@ function(configureProject) add_definitions(-DETH_CURL) endif() - add_definitions(-DNOBOOST) + if (NOBOOST) + add_definitions(-DNOBOOST) + endif() + add_definitions(-DETH_TRUE) endfunction() @@ -196,6 +199,7 @@ eth_format_option(MINER) eth_format_option(USENPM) eth_format_option(PROFILING) eth_format_option(SOLIDITY) +eth_format_option(ROCKSDB) eth_format_option(GUI) eth_format_option(TESTS) eth_format_option(NOBOOST) @@ -311,6 +315,7 @@ message("-- PROFILING Profiling support ${PROFILIN message("-- FATDB Full database exploring ${FATDB}") message("-- JSONRPC JSON-RPC support ${JSONRPC}") message("-- USENPM Javascript source building ${USENPM}") +message("-- ROCKSDB Prefer rocksdb to leveldb ${ROCKSDB}") message("------------------------------------------------------------- components") message("-- MINER Build miner ${MINER}") message("-- ETHKEY Build wallet tools ${ETHKEY}") @@ -337,6 +342,15 @@ include(EthExecutableHelper) createBuildInfo() +if (ROCKSDB AND ROCKSDB_FOUND) + set(DB_INCLUDE_DIRS ${ROCKSDB_INCLUDE_DIRS}) + set(DB_LIBRARIES ${ROCKSDB_LIBRARIES}) + add_definitions(-DETH_ROCKSDB) +else() + set(DB_INCLUDE_DIRS ${LEVELDB_INCLUDE_DIRS}) + set(DB_LIBRARIES ${LEVELDB_LIBRARIES}) +endif() + if (EVMJIT) set(EVMJIT_CPP TRUE) # include CPP-JIT connector add_subdirectory(evmjit) @@ -380,6 +394,7 @@ endif () if (JSCONSOLE) add_subdirectory(libjsengine) add_subdirectory(libjsconsole) + add_subdirectory(ethconsole) endif () add_subdirectory(secp256k1) diff --git a/abi/CMakeLists.txt b/abi/CMakeLists.txt index 3cc6b2594..96ca9b620 100644 --- a/abi/CMakeLists.txt +++ b/abi/CMakeLists.txt @@ -4,7 +4,7 @@ set(CMAKE_AUTOMOC OFF) aux_source_directory(. SRC_LIST) include_directories(BEFORE ..) -include_directories(${LEVELDB_INCLUDE_DIRS}) +include_directories(${DB_INCLUDE_DIRS}) set(EXECUTABLE abi) diff --git a/alethzero/DappLoader.cpp b/alethzero/DappLoader.cpp index 662a1afbc..5ef784e3a 100644 --- a/alethzero/DappLoader.cpp +++ b/alethzero/DappLoader.cpp @@ -193,6 +193,8 @@ QByteArray const& DappLoader::web3Content() code += "\n"; code += contentsOfQResource(":/js/setup.js"); code += "\n"; + code += contentsOfQResource(":/js/admin.js"); + code += "\n"; m_web3Js = code.toLatin1(); } return m_web3Js; diff --git a/alethzero/NatspecHandler.h b/alethzero/NatspecHandler.h index 241df4e06..de0f1403b 100644 --- a/alethzero/NatspecHandler.h +++ b/alethzero/NatspecHandler.h @@ -22,16 +22,11 @@ #pragma once -#pragma warning(push) -#pragma warning(disable: 4100 4267) -#include -#pragma warning(pop) +#include #include #include #include "Context.h" -namespace ldb = leveldb; - class NatspecHandler: public NatSpecFace { public: diff --git a/alethzero/Transact.cpp b/alethzero/Transact.cpp index 7a26f56f2..594133ba4 100644 --- a/alethzero/Transact.cpp +++ b/alethzero/Transact.cpp @@ -139,7 +139,7 @@ void Transact::updateDestination() void Transact::updateFee() { - ui->fee->setText(QString("(gas sub-total: %1)").arg(formatBalance(fee()).c_str())); +// ui->fee->setText(QString("(gas sub-total: %1)").arg(formatBalance(fee()).c_str())); auto totalReq = total(); ui->total->setText(QString("Total: %1").arg(formatBalance(totalReq).c_str())); @@ -435,9 +435,18 @@ Address Transact::fromAccount() return *it; } +void Transact::updateNonce() +{ + u256 n = ethereum()->countAt(fromAccount(), PendingBlock); + ui->nonce->setMaximum((unsigned)n); + ui->nonce->setMinimum(0); + ui->nonce->setValue((unsigned)n); +} + void Transact::on_send_clicked() { // Secret s = findSecret(value() + fee()); + u256 nonce = ui->autoNonce->isChecked() ? ethereum()->countAt(fromAccount(), PendingBlock) : ui->nonce->value(); auto a = fromAccount(); auto b = ethereum()->balanceAt(a, PendingBlock); @@ -455,7 +464,7 @@ void Transact::on_send_clicked() { // If execution is a contract creation, add Natspec to // a local Natspec LEVELDB - ethereum()->submitTransaction(s, value(), m_data, ui->gas->value(), gasPrice()); + ethereum()->submitTransaction(s, value(), m_data, ui->gas->value(), gasPrice(), nonce); #if ETH_SOLIDITY string src = ui->data->toPlainText().toStdString(); if (sourceIsSolidity(src)) @@ -474,7 +483,7 @@ void Transact::on_send_clicked() } else // TODO: cache like m_data. - ethereum()->submitTransaction(s, value(), m_context->fromString(ui->destination->currentText().toStdString()).first, m_data, ui->gas->value(), gasPrice()); + ethereum()->submitTransaction(s, value(), m_context->fromString(ui->destination->currentText().toStdString()).first, m_data, ui->gas->value(), gasPrice(), nonce); close(); } diff --git a/alethzero/Transact.h b/alethzero/Transact.h index b8b5134a4..e2c1a6662 100644 --- a/alethzero/Transact.h +++ b/alethzero/Transact.h @@ -45,7 +45,7 @@ public: void setEnvironment(dev::AddressHash const& _accounts, dev::eth::Client* _eth, NatSpecFace* _natSpecDB); private slots: - void on_from_currentIndexChanged(int) { rejigData(); rejigData(); } + void on_from_currentIndexChanged(int) { updateNonce(); rejigData(); } void on_destination_currentTextChanged(QString); void on_value_valueChanged(int) { updateFee(); rejigData(); } void on_gas_valueChanged(int) { updateFee(); rejigData(); } @@ -61,6 +61,7 @@ private slots: private: dev::eth::Client* ethereum() const { return m_ethereum; } void rejigData(); + void updateNonce(); dev::Address fromAccount(); void updateDestination(); diff --git a/alethzero/Transact.ui b/alethzero/Transact.ui index 87a8ebd99..fe1fc4c3e 100644 --- a/alethzero/Transact.ui +++ b/alethzero/Transact.ui @@ -14,35 +14,6 @@ Transact - - - - - 0 - 0 - - - - D&ata - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - data - - - - - - - &Optimise - - - true - - - @@ -92,6 +63,9 @@ + + + @@ -105,22 +79,6 @@ - - - - - - - 430000000 - - - 0 - - - - - - @@ -166,6 +124,54 @@ + + + + + 0 + 0 + + + + D&ata + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + data + + + + + + + + + + + + + 430000000 + + + 0 + + + + + + + false + + + true + + + + + + @@ -205,53 +211,68 @@ - - - - false - - - true + + + + &From - - + + from - - + + - - - - - 0 - 0 - - + + - + &Optimise - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + true - - + + + + false + + + + + - &From + Auto Nonce - - from + + true + + + false - - - - + + + autoNonce + toggled(bool) + nonce + setDisabled(bool) + + + 374 + 196 + + + 451 + 190 + + + + diff --git a/cmake/EthCompilerSettings.cmake b/cmake/EthCompilerSettings.cmake index 85574d5f0..6701cf824 100644 --- a/cmake/EthCompilerSettings.cmake +++ b/cmake/EthCompilerSettings.cmake @@ -19,6 +19,7 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wno-unknown-pragmas -Wextra -DSHAREDLIB -fPIC") set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DETH_DEBUG") + set(CMAKE_CXX_FLAGS_DEBUGSAN "-O1 -g -fsanitize=address,integer,undefined -fsanitize-blacklist=${CMAKE_SOURCE_DIR}/sanitizer-blacklist.txt -fno-omit-frame-pointer -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_RELEASE") diff --git a/cmake/EthDependencies.cmake b/cmake/EthDependencies.cmake index 9a18a98e7..86415f2dd 100644 --- a/cmake/EthDependencies.cmake +++ b/cmake/EthDependencies.cmake @@ -49,6 +49,12 @@ find_package (LevelDB REQUIRED) message(" - LevelDB header: ${LEVELDB_INCLUDE_DIRS}") message(" - LevelDB lib: ${LEVELDB_LIBRARIES}") +find_package (RocksDB) +if (ROCKSDB_FOUND) + message(" - RocksDB header: ${ROCKSDB_INCLUDE_DIRS}") + message(" - RocksDB lib: ${ROCKSDB_LIBRARIES}") +endif() + if (JSCONSOLE) find_package (v8 REQUIRED) message(" - v8 header: ${V8_INCLUDE_DIRS}") diff --git a/cmake/FindRocksDB.cmake b/cmake/FindRocksDB.cmake new file mode 100644 index 000000000..168930bc7 --- /dev/null +++ b/cmake/FindRocksDB.cmake @@ -0,0 +1,49 @@ +# Find rocksdb +# +# Find the rocksdb includes and library +# +# if you nee to add a custom library search path, do it via via CMAKE_PREFIX_PATH +# +# This module defines +# ROCKSDB_INCLUDE_DIRS, where to find header, etc. +# ROCKSDB_LIBRARIES, the libraries needed to use rocksdb. +# ROCKSDB_FOUND, If false, do not try to use rocksdb. + +# only look in default directories +find_path( + ROCKSDB_INCLUDE_DIR + NAMES rocksdb/db.h + DOC "rocksdb include dir" +) + +find_library( + ROCKSDB_LIBRARY + NAMES rocksdb + DOC "rocksdb library" +) + +set(ROCKSDB_INCLUDE_DIRS ${ROCKSDB_INCLUDE_DIR}) +set(ROCKSDB_LIBRARIES ${ROCKSDB_LIBRARY}) + +# debug library on windows +# same naming convention as in qt (appending debug library with d) +# boost is using the same "hack" as us with "optimized" and "debug" +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + + find_library( + ROCKSDB_LIBRARY_DEBUG + NAMES rocksdbd + DOC "rocksdb debug library" + ) + + set(ROCKSDB_LIBRARIES optimized ${ROCKSDB_LIBRARIES} debug ${ROCKSDB_LIBRARY_DEBUG}) + +endif() + +# handle the QUIETLY and REQUIRED arguments and set ROCKSDB_FOUND to TRUE +# if all listed variables are TRUE, hide their existence from configuration view +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(rocksdb DEFAULT_MSG + ROCKSDB_INCLUDE_DIR ROCKSDB_LIBRARY) +mark_as_advanced (ROCKSDB_INCLUDE_DIR ROCKSDB_LIBRARY) + diff --git a/eth/main.cpp b/eth/main.cpp index c5a15e5fd..235183ef6 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -41,7 +41,7 @@ #include #if ETH_JSCONSOLE || !ETH_TRUE -#include +#include #endif #if ETH_READLINE || !ETH_TRUE #include @@ -141,6 +141,7 @@ void help() << " --master Give the master password for the key store." << endl << " --password Give a password for a private key." << endl << " --sentinel Set the sentinel for reporting bad blocks or chain issues." << endl + << " --prime Specify n as the 6 digit prime number to start Frontier." << endl << endl << "Client transacting:" << endl /*<< " -B,--block-fees Set the block fee profit in the reference unit e.g. ¢ (default: 15)." << endl @@ -187,6 +188,7 @@ void help() << " --from Export only from block n; n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl << " --to Export only to block n (inclusive); n may be a decimal, a '0x' prefixed hash, or 'latest'." << endl << " --only Equivalent to --export-from n --export-to n." << endl + << " --dont-check Avoids checking some of the aspects of blocks. Faster importing, but only do if you know the data is valid." << endl << endl << "General Options:" << endl << " -d,--db-path Load database from path (default: " << getDataDir() << ")" << endl @@ -240,6 +242,16 @@ string pretty(h160 _a, dev::eth::State const& _st) bool g_exit = false; +inline bool isPrime(unsigned _number) +{ + if (((!(_number & 1)) && _number != 2 ) || (_number < 2) || (_number % 3 == 0 && _number != 3)) + return false; + for(unsigned k = 1; 36 * k * k - 12 * k < _number; ++k) + if ((_number % (6 * k + 1) == 0) || (_number % (6 * k - 1) == 0)) + return false; + return true; +} + void sighandler(int) { g_exit = true; @@ -280,9 +292,12 @@ int main(int argc, char** argv) /// Operating mode. OperationMode mode = OperationMode::Node; string dbPath; + unsigned prime = 0; + bool yesIReallyKnowWhatImDoing = false; /// File name for import/export. string filename; + bool safeImport = false; /// Hashes/numbers for export range. string exportFrom = "1"; @@ -395,11 +410,25 @@ int main(int argc, char** argv) mode = OperationMode::Import; filename = argv[++i]; } + else if (arg == "--dont-check") + safeImport = true; else if ((arg == "-E" || arg == "--export") && i + 1 < argc) { mode = OperationMode::Export; filename = argv[++i]; } + else if (arg == "--prime" && i + 1 < argc) + try + { + prime = stoi(argv[++i]); + } + catch (...) + { + cerr << "Bad " << arg << " option: " << argv[i] << endl; + return -1; + } + else if (arg == "--yes-i-really-know-what-im-doing") + yesIReallyKnowWhatImDoing = true; else if (arg == "--sentinel" && i + 1 < argc) sentinel = argv[++i]; else if (arg == "--mine-on-wrong-chain") @@ -753,13 +782,18 @@ int main(int argc, char** argv) unsigned futureTime = 0; unsigned unknownParent = 0; unsigned bad = 0; + chrono::steady_clock::time_point t = chrono::steady_clock::now(); + double last = 0; + unsigned lastImported = 0; + unsigned imported = 0; while (in.peek() != -1) { bytes block(8); in.read((char*)block.data(), 8); block.resize(RLP(block, RLP::LaisezFaire).actualSize()); in.read((char*)block.data() + 8, block.size() - 8); - switch (web3.ethereum()->injectBlock(block)) + + switch (web3.ethereum()->queueBlock(block, safeImport)) { case ImportResult::Success: good++; break; case ImportResult::AlreadyKnown: alreadyHave++; break; @@ -768,11 +802,52 @@ int main(int argc, char** argv) case ImportResult::FutureTimeKnown: futureTime++; break; default: bad++; break; } + + // sync chain with queue + tuple r = web3.ethereum()->syncQueue(10); + imported += get<2>(r); + + double e = chrono::duration_cast(chrono::steady_clock::now() - t).count() / 1000.0; + if ((unsigned)e >= last + 10) + { + auto i = imported - lastImported; + auto d = e - last; + cout << i << " more imported at " << (round(i * 10 / d) / 10) << " blocks/s. " << imported << " imported in " << e << " seconds at " << (round(imported * 10 / e) / 10) << " blocks/s (#" << web3.ethereum()->number() << ")" << endl; + last = (unsigned)e; + lastImported = imported; + } } - cout << (good + bad + futureTime + unknownParent + alreadyHave) << " total: " << good << " ok, " << alreadyHave << " got, " << futureTime << " future, " << unknownParent << " unknown parent, " << bad << " malformed." << endl; + + while (web3.ethereum()->blockQueue().items().first + web3.ethereum()->blockQueue().items().second > 0) + { + sleep(1); + web3.ethereum()->syncQueue(100000); + } + double e = chrono::duration_cast(chrono::steady_clock::now() - t).count() / 1000.0; + cout << imported << " imported in " << e << " seconds at " << (round(imported * 10 / e) / 10) << " blocks/s (#" << web3.ethereum()->number() << ")" << endl; return 0; } + if (c_network == eth::Network::Frontier && !yesIReallyKnowWhatImDoing) + { + auto pd = contents(getDataDir() + "primes"); + unordered_set primes = RLP(pd).toUnorderedSet(); + while (true) + { + if (!prime) + try + { + prime = stoi(getPassword("To enter the Frontier, enter a 6 digit prime that you have not entered before: ")); + } + catch (...) {} + if (isPrime(prime) && !primes.count(prime)) + break; + prime = 0; + } + primes.insert(prime); + writeFile(getDataDir() + "primes", rlp(primes)); + } + if (keyManager.exists()) { if (masterPassword.empty() || !keyManager.load(masterPassword)) @@ -1742,12 +1817,24 @@ int main(int argc, char** argv) if (useConsole) { #if ETH_JSCONSOLE - JSConsole console(web3, make_shared([&](){return web3.ethereum();}, getAccountPassword, keyManager)); + JSLocalConsole console; + + jsonrpcServer = shared_ptr(new dev::WebThreeStubServer(*jsonrpcConnector.get(), web3, make_shared([&](){ return web3.ethereum(); }, getAccountPassword, keyManager), vector(), keyManager, *gasPricer)); + jsonrpcServer->setMiningBenefactorChanger([&](Address const& a) { beneficiary = a; }); + jsonrpcServer->StartListening(); + if (jsonAdmin.empty()) + jsonAdmin = jsonrpcServer->newSession(SessionPermissions{{Priviledge::Admin}}); + else + jsonrpcServer->addSession(jsonAdmin, SessionPermissions{{Priviledge::Admin}}); + cout << "JSONRPC Admin Session Key: " << jsonAdmin << endl; + while (!g_exit) { console.readExpression(); stopMiningAfterXBlocks(c, n, mining); } + + jsonrpcServer->StopListening(); #endif } else diff --git a/ethconsole/CMakeLists.txt b/ethconsole/CMakeLists.txt new file mode 100644 index 000000000..08fa7ca83 --- /dev/null +++ b/ethconsole/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_policy(SET CMP0015 NEW) +set(CMAKE_AUTOMOC OFF) + +aux_source_directory(. SRC_LIST) + +include_directories(BEFORE ..) +include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) +include_directories(${CURL_INCLUDE_DIRS}) +include_directories(${V8_INCLUDE_DIRS}) + +set(EXECUTABLE ethconsole) + +file(GLOB HEADERS "*.h") + +add_executable(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) + +target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES}) +target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES}) +target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES}) + +if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) + eth_copy_dlls(${EXECUTABLE} CURL_DLLS) +endif() +target_link_libraries(${EXECUTABLE} jsconsole) + +if (APPLE) + install(TARGETS ${EXECUTABLE} DESTINATION bin) +else() + eth_install_executable(${EXECUTABLE}) +endif() + diff --git a/ethconsole/main.cpp b/ethconsole/main.cpp new file mode 100644 index 000000000..5df3444eb --- /dev/null +++ b/ethconsole/main.cpp @@ -0,0 +1,41 @@ +/* + 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 Marek + * @date 2014 + */ + +#include +#include +using namespace std; +using namespace dev; +using namespace dev::eth; + +int main(int argc, char** argv) +{ + string remote; + if (argc == 1) + remote = "http://localhost:8545"; + else if (argc == 2) + remote = argv[1]; + + JSRemoteConsole console(remote); + while (true) + console.readExpression(); + + return 0; +} diff --git a/ethkey/KeyAux.h b/ethkey/KeyAux.h index 11de30e39..ae8eaed92 100644 --- a/ethkey/KeyAux.h +++ b/ethkey/KeyAux.h @@ -198,7 +198,16 @@ public: if (m_masterPassword.empty()) cerr << "Aborted (empty password not allowed)." << endl; else - wallet.create(m_masterPassword); + { + try + { + wallet.create(m_masterPassword); + } + catch (Exception const& _e) + { + cerr << "unable to create wallet" << endl << boost::diagnostic_information(_e); + } + } } else if (m_mode < OperationMode::CreateWallet) { diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index a609754dd..e123cdbb1 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -107,7 +107,7 @@ public: catch (...) { cerr << "Bad " << arg << " option: " << argv[i] << endl; - throw BadArgument(); + BOOST_THROW_EXCEPTION(BadArgument()); } else if (arg == "--opencl-platform" && i + 1 < argc) try { @@ -116,7 +116,7 @@ public: catch (...) { cerr << "Bad " << arg << " option: " << argv[i] << endl; - throw BadArgument(); + BOOST_THROW_EXCEPTION(BadArgument()); } else if (arg == "--opencl-device" && i + 1 < argc) try { @@ -126,7 +126,7 @@ public: catch (...) { cerr << "Bad " << arg << " option: " << argv[i] << endl; - throw BadArgument(); + BOOST_THROW_EXCEPTION(BadArgument()); } else if (arg == "--list-devices") m_shouldListDevices = true; @@ -144,7 +144,7 @@ public: else { cerr << "Bad " << arg << " option: " << m << endl; - throw BadArgument(); + BOOST_THROW_EXCEPTION(BadArgument()); } } else if (arg == "--benchmark-warmup" && i + 1 < argc) @@ -154,7 +154,7 @@ public: catch (...) { cerr << "Bad " << arg << " option: " << argv[i] << endl; - throw BadArgument(); + BOOST_THROW_EXCEPTION(BadArgument()); } else if (arg == "--benchmark-trial" && i + 1 < argc) try { @@ -163,7 +163,7 @@ public: catch (...) { cerr << "Bad " << arg << " option: " << argv[i] << endl; - throw BadArgument(); + BOOST_THROW_EXCEPTION(BadArgument()); } else if (arg == "--benchmark-trials" && i + 1 < argc) try { @@ -172,7 +172,7 @@ public: catch (...) { cerr << "Bad " << arg << " option: " << argv[i] << endl; - throw BadArgument(); + BOOST_THROW_EXCEPTION(BadArgument()); } else if (arg == "-C" || arg == "--cpu") m_minerType = MinerType::CPU; @@ -195,7 +195,7 @@ public: catch (...) { cerr << "Bad " << arg << " option: " << m << endl; - throw BadArgument(); + BOOST_THROW_EXCEPTION(BadArgument()); } } else if ((arg == "-w" || arg == "--check-pow") && i + 4 < argc) @@ -232,7 +232,7 @@ public: catch (...) { cerr << "Bad " << arg << " option: " << m << endl; - throw BadArgument(); + BOOST_THROW_EXCEPTION(BadArgument()); } } else if (arg == "-M" || arg == "--benchmark") @@ -245,7 +245,7 @@ public: catch (...) { cerr << "Bad " << arg << " option: " << argv[i] << endl; - throw BadArgument(); + BOOST_THROW_EXCEPTION(BadArgument()); } } else diff --git a/ethvm/CMakeLists.txt b/ethvm/CMakeLists.txt index ed093061c..9b7e7f25d 100644 --- a/ethvm/CMakeLists.txt +++ b/ethvm/CMakeLists.txt @@ -4,7 +4,7 @@ set(CMAKE_AUTOMOC OFF) aux_source_directory(. SRC_LIST) include_directories(BEFORE ..) -include_directories(${LEVELDB_INCLUDE_DIRS}) +include_directories(${DB_INCLUDE_DIRS}) set(EXECUTABLE ethvm) diff --git a/ethvm/main.cpp b/ethvm/main.cpp index 08a1b4508..4ca733ed0 100644 --- a/ethvm/main.cpp +++ b/ethvm/main.cpp @@ -165,7 +165,7 @@ int main(int argc, char** argv) executive.initialize(t); executive.create(sender, value, gasPrice, gas, &data, origin); - boost::timer timer; + Timer timer; executive.go(onOp); double execTime = timer.elapsed(); executive.finalize(); diff --git a/evmjit/CMakeLists.txt b/evmjit/CMakeLists.txt index 280fec212..70d3e1dda 100644 --- a/evmjit/CMakeLists.txt +++ b/evmjit/CMakeLists.txt @@ -10,28 +10,17 @@ else() set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -Wextra -Wconversion -Wno-sign-conversion -Wno-unknown-pragmas ${CMAKE_CXX_FLAGS}") endif() -if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") +if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND NOT ${CMAKE_BUILD_TYPE} STREQUAL "DebugSan") # Do not allow unresovled symbols in shared library (default on linux) set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined") endif() # LLVM -if(LLVM_DIR OR APPLE) # local LLVM build - find_package(LLVM REQUIRED CONFIG) - message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") - message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") - add_definitions(${LLVM_DEFINITIONS}) - # TODO: bitwriter is needed only for evmcc - llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen bitwriter ipo) -else() - # Workaround for Ubuntu broken LLVM package - message(STATUS "Using llvm-3.5-dev package from Ubuntu. If does not work, build LLVM and set -DLLVM_DIR=llvm-build/share/llvm/cmake") - execute_process(COMMAND llvm-config-3.5 --includedir OUTPUT_VARIABLE LLVM_INCLUDE_DIRS) - message(STATUS "LLVM include dirs: ${LLVM_INCLUDE_DIRS}") - set(LLVM_LIBS "-lLLVMBitWriter -lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMX86AsmParser -lLLVMX86Desc -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMMCJIT -lLLVMTarget -lLLVMRuntimeDyld -lLLVMObject -lLLVMMCParser -lLLVMBitReader -lLLVMExecutionEngine -lLLVMMC -lLLVMCore -lLLVMSupport -lz -lpthread -lffi -ltinfo -ldl -lm") - add_definitions(-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS) - link_directories(/usr/lib/llvm-3.5/lib) -endif() +find_package(LLVM 3.7 REQUIRED CONFIG) +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") +message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") +add_definitions(${LLVM_DEFINITIONS}) +llvm_map_components_to_libnames(LLVM_LIBS core support mcjit x86asmparser x86codegen ipo) get_filename_component(EVMJIT_INCLUDE_DIR include ABSOLUTE) diff --git a/evmjit/libevmjit/Arith256.cpp b/evmjit/libevmjit/Arith256.cpp index e88fda432..95ca2aee5 100644 --- a/evmjit/libevmjit/Arith256.cpp +++ b/evmjit/libevmjit/Arith256.cpp @@ -167,21 +167,10 @@ llvm::Function* Arith256::getDivFunc(llvm::Type* _type) m_builder.SetInsertPoint(mainBB); auto ctlzIntr = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, _type); // both y and r are non-zero - auto yLz = m_builder.CreateCall2(ctlzIntr, yArg, m_builder.getInt1(true), "y.lz"); - auto rLz = m_builder.CreateCall2(ctlzIntr, r0, m_builder.getInt1(true), "r.lz"); + auto yLz = m_builder.CreateCall(ctlzIntr, {yArg, m_builder.getInt1(true)}, "y.lz"); + auto rLz = m_builder.CreateCall(ctlzIntr, {r0, m_builder.getInt1(true)}, "r.lz"); auto i0 = m_builder.CreateNUWSub(yLz, rLz, "i0"); - auto shlBy0 = m_builder.CreateICmpEQ(i0, zero); auto y0 = m_builder.CreateShl(yArg, i0); - if (_type == m_builder.getIntNTy(512)) // Workaround for shl bug for long shifts - { - const auto treshold = m_builder.getIntN(512, 128); - auto highShift = m_builder.CreateICmpUGT(i0, treshold); - auto s = m_builder.CreateNUWSub(i0, treshold); - auto yhs = m_builder.CreateShl(yArg, treshold); - yhs = m_builder.CreateShl(yhs, s); - y0 = m_builder.CreateSelect(highShift, yhs, y0); - } - y0 = m_builder.CreateSelect(shlBy0, yArg, y0, "y0"); // Workaround for LLVM bug: shl by 0 produces wrong result m_builder.CreateBr(loopBB); m_builder.SetInsertPoint(loopBB); diff --git a/evmjit/libevmjit/Array.cpp b/evmjit/libevmjit/Array.cpp index 0b511a058..9a7f18597 100644 --- a/evmjit/libevmjit/Array.cpp +++ b/evmjit/libevmjit/Array.cpp @@ -45,9 +45,9 @@ llvm::Function* Array::createArrayPushFunc() auto pushBB = llvm::BasicBlock::Create(m_builder.getContext(), "Push", func); m_builder.SetInsertPoint(entryBB); - auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr"); - auto sizePtr = m_builder.CreateStructGEP(arrayPtr, 1, "sizePtr"); - auto capPtr = m_builder.CreateStructGEP(arrayPtr, 2, "capPtr"); + auto dataPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 0, "dataPtr"); + auto sizePtr = m_builder.CreateStructGEP(getType(), arrayPtr, 1, "sizePtr"); + auto capPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 2, "capPtr"); auto data = m_builder.CreateLoad(dataPtr, "data"); auto size = m_builder.CreateLoad(sizePtr, "size"); auto cap = m_builder.CreateLoad(capPtr, "cap"); @@ -94,7 +94,7 @@ llvm::Function* Array::createArraySetFunc() InsertPointGuard guard{m_builder}; m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); - auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr"); + auto dataPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 0, "dataPtr"); auto data = m_builder.CreateLoad(dataPtr, "data"); auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr"); m_builder.CreateStore(value, valuePtr); @@ -116,7 +116,7 @@ llvm::Function* Array::createArrayGetFunc() InsertPointGuard guard{m_builder}; m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); - auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr"); + auto dataPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 0, "dataPtr"); auto data = m_builder.CreateLoad(dataPtr, "data"); auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr"); auto value = m_builder.CreateLoad(valuePtr, "value"); @@ -161,7 +161,7 @@ llvm::Function* Array::createFreeFunc() InsertPointGuard guard{m_builder}; m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); - auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr"); + auto dataPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 0, "dataPtr"); auto data = m_builder.CreateLoad(dataPtr, "data"); auto mem = m_builder.CreateBitCast(data, Type::BytePtr, "mem"); m_builder.CreateCall(freeFunc, mem); @@ -197,8 +197,8 @@ llvm::Function* Array::createExtendFunc() InsertPointGuard guard{m_builder}; m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func)); auto dataPtr = m_builder.CreateBitCast(arrayPtr, Type::BytePtr->getPointerTo(), "dataPtr");// TODO: Use byte* in Array - auto sizePtr = m_builder.CreateStructGEP(arrayPtr, 1, "sizePtr"); - auto capPtr = m_builder.CreateStructGEP(arrayPtr, 2, "capPtr"); + auto sizePtr = m_builder.CreateStructGEP(getType(), arrayPtr, 1, "sizePtr"); + auto capPtr = m_builder.CreateStructGEP(getType(), arrayPtr, 2, "capPtr"); auto data = m_builder.CreateLoad(dataPtr, "data"); auto size = m_builder.CreateLoad(sizePtr, "size"); auto extSize = m_builder.CreateNUWSub(newSize, size, "extSize"); @@ -244,7 +244,7 @@ Array::Array(llvm::IRBuilder<>& _builder, llvm::Value* _array) : void Array::pop(llvm::Value* _count) { - auto sizePtr = m_builder.CreateStructGEP(m_array, 1, "sizePtr"); + auto sizePtr = m_builder.CreateStructGEP(getType(), m_array, 1, "sizePtr"); auto size = m_builder.CreateLoad(sizePtr, "size"); auto newSize = m_builder.CreateNUWSub(size, _count, "newSize"); m_builder.CreateStore(newSize, sizePtr); @@ -252,7 +252,7 @@ void Array::pop(llvm::Value* _count) llvm::Value* Array::size(llvm::Value* _array) { - auto sizePtr = m_builder.CreateStructGEP(_array ? _array : m_array, 1, "sizePtr"); + auto sizePtr = m_builder.CreateStructGEP(getType(), _array ? _array : m_array, 1, "sizePtr"); return m_builder.CreateLoad(sizePtr, "array.size"); } diff --git a/evmjit/libevmjit/Cache.cpp b/evmjit/libevmjit/Cache.cpp index 42ccf44ac..36dae3763 100644 --- a/evmjit/libevmjit/Cache.cpp +++ b/evmjit/libevmjit/Cache.cpp @@ -28,7 +28,7 @@ namespace using Guard = std::lock_guard; std::mutex x_cacheMutex; CacheMode g_mode; - llvm::MemoryBuffer* g_lastObject; + std::unique_ptr g_lastObject; ExecutionEngineListener* g_listener; static const size_t c_versionStampLength = 32; @@ -90,8 +90,7 @@ void Cache::preload(llvm::ExecutionEngine& _ee, std::unordered_map Cache::getObject(std::string const& id) } -void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) +void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBufferRef _object) { Guard g{x_cacheMutex}; @@ -171,19 +170,17 @@ void ObjectCache::notifyObjectCompiled(llvm::Module const* _module, llvm::Memory llvm::sys::path::append(cachePath, id); DLOG(cache) << id << ": write\n"; - std::string error; + std::error_code error; llvm::raw_fd_ostream cacheFile(cachePath.c_str(), error, llvm::sys::fs::F_None); - cacheFile << _object->getBuffer() << getLibVersionStamp(); + cacheFile << _object.getBuffer() << getLibVersionStamp(); } -llvm::MemoryBuffer* ObjectCache::getObject(llvm::Module const* _module) +std::unique_ptr ObjectCache::getObject(llvm::Module const* _module) { Guard g{x_cacheMutex}; DLOG(cache) << _module->getModuleIdentifier() << ": use\n"; - auto o = g_lastObject; - g_lastObject = nullptr; - return o; + return std::move(g_lastObject); } } diff --git a/evmjit/libevmjit/Cache.h b/evmjit/libevmjit/Cache.h index f6a0a3400..1d5927705 100644 --- a/evmjit/libevmjit/Cache.h +++ b/evmjit/libevmjit/Cache.h @@ -3,7 +3,9 @@ #include #include +#include "preprocessor/llvm_includes_start.h" #include +#include "preprocessor/llvm_includes_end.h" namespace llvm { @@ -32,13 +34,13 @@ class ObjectCache : public llvm::ObjectCache { public: /// notifyObjectCompiled - Provides a pointer to compiled code for Module M. - virtual void notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBuffer const* _object) final override; + virtual void notifyObjectCompiled(llvm::Module const* _module, llvm::MemoryBufferRef _object) final override; /// getObjectCopy - Returns a pointer to a newly allocated MemoryBuffer that /// contains the object which corresponds with Module M, or 0 if an object is /// not available. The caller owns both the MemoryBuffer returned by this /// and the memory it references. - virtual llvm::MemoryBuffer* getObject(llvm::Module const* _module) final override; + virtual std::unique_ptr getObject(llvm::Module const* _module) final override; }; diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index 1e1f8fe93..e49979294 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/evmjit/libevmjit/Compiler.cpp @@ -148,7 +148,7 @@ std::unique_ptr Compiler::compile(code_iterator _begin, code_itera auto fp = m_builder.CreateCall(frameaddress, m_builder.getInt32(0), "fp"); m_builder.CreateStore(fp, jmpBufWords); auto stacksave = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::stacksave); - auto sp = m_builder.CreateCall(stacksave, "sp"); + auto sp = m_builder.CreateCall(stacksave, {}, "sp"); auto jmpBufSp = m_builder.CreateConstInBoundsGEP1_64(jmpBufWords, 2, "jmpBuf.sp"); m_builder.CreateStore(sp, jmpBufSp); auto setjmp = llvm::Intrinsic::getDeclaration(module.get(), llvm::Intrinsic::eh_sjlj_setjmp); @@ -464,12 +464,8 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti // test for word >> (k * 8 + 7) auto bitpos = m_builder.CreateAdd(k32x8, m_builder.getInt64(7), "bitpos"); auto bitposEx = m_builder.CreateZExt(bitpos, Type::Word); - auto bittester = m_builder.CreateShl(Constant::get(1), bitposEx); - auto bitresult = m_builder.CreateAnd(word, bittester); - auto bittest = m_builder.CreateICmpUGT(bitresult, Constant::get(0)); - // FIXME: The following does not work - LLVM bug, report! - //auto bitval = m_builder.CreateLShr(word, bitpos, "bitval"); - //auto bittest = m_builder.CreateTrunc(bitval, Type::Bool, "bittest"); + auto bitval = m_builder.CreateLShr(word, bitposEx, "bitval"); + auto bittest = m_builder.CreateTrunc(bitval, Type::Bool, "bittest"); auto mask_ = m_builder.CreateShl(Constant::get(1), bitposEx); auto mask = m_builder.CreateSub(mask_, Constant::get(1), "mask"); diff --git a/evmjit/libevmjit/Endianness.cpp b/evmjit/libevmjit/Endianness.cpp index d36f4b7fa..25b66c0d5 100644 --- a/evmjit/libevmjit/Endianness.cpp +++ b/evmjit/libevmjit/Endianness.cpp @@ -18,9 +18,8 @@ llvm::Value* Endianness::bswapIfLE(llvm::IRBuilder<>& _builder, llvm::Value* _wo { if (llvm::sys::IsLittleEndianHost) { - // FIXME: Disabled because of problems with BYTE - //if (auto constant = llvm::dyn_cast(_word)) - // return _builder.getInt(constant->getValue().byteSwap()); + if (auto constant = llvm::dyn_cast(_word)) + return _builder.getInt(constant->getValue().byteSwap()); // OPT: Cache func declaration? auto bswapFunc = llvm::Intrinsic::getDeclaration(_builder.GetInsertBlock()->getParent()->getParent(), llvm::Intrinsic::bswap, Type::Word); diff --git a/evmjit/libevmjit/ExecutionEngine.cpp b/evmjit/libevmjit/ExecutionEngine.cpp index e5abb36b3..a5b26401f 100644 --- a/evmjit/libevmjit/ExecutionEngine.cpp +++ b/evmjit/libevmjit/ExecutionEngine.cpp @@ -87,20 +87,7 @@ void parseOptions() { static llvm::llvm_shutdown_obj shutdownObj{}; cl::AddExtraVersionPrinter(printVersion); - //cl::ParseEnvironmentOptions("evmjit", "EVMJIT", "Ethereum EVM JIT Compiler"); - - // FIXME: LLVM workaround: - // Manually select instruction scheduler. Confirmed bad schedulers: source, list-burr, list-hybrid. - // "source" scheduler has a bug: http://llvm.org/bugs/show_bug.cgi?id=22304 - auto envLine = std::getenv("EVMJIT"); - auto commandLine = std::string{"evmjit "} + (envLine ? envLine : "") + " -pre-RA-sched=list-ilp\0"; - static const auto c_maxArgs = 20; - char const* argv[c_maxArgs] = {nullptr, }; - auto arg = std::strtok(&*commandLine.begin(), " "); - auto i = 0; - for (; i < c_maxArgs && arg; ++i, arg = std::strtok(nullptr, " ")) - argv[i] = arg; - cl::ParseCommandLineOptions(i, argv, "Ethereum EVM JIT Compiler"); + cl::ParseEnvironmentOptions("evmjit", "EVMJIT", "Ethereum EVM JIT Compiler"); } } @@ -131,20 +118,20 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) llvm::InitializeNativeTargetAsmPrinter(); auto module = std::unique_ptr(new llvm::Module({}, llvm::getGlobalContext())); - llvm::EngineBuilder builder(module.get()); - builder.setEngineKind(llvm::EngineKind::JIT); - builder.setUseMCJIT(true); - builder.setOptLevel(g_optimize ? llvm::CodeGenOpt::Default : llvm::CodeGenOpt::None); + // FIXME: LLVM 3.7: test on Windows auto triple = llvm::Triple(llvm::sys::getProcessTriple()); if (triple.getOS() == llvm::Triple::OSType::Win32) triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF); // MCJIT does not support COFF format module->setTargetTriple(triple.str()); + llvm::EngineBuilder builder(std::move(module)); + builder.setEngineKind(llvm::EngineKind::JIT); + builder.setOptLevel(g_optimize ? llvm::CodeGenOpt::Default : llvm::CodeGenOpt::None); + ee.reset(builder.create()); if (!CHECK(ee)) return ReturnCode::LLVMConfigError; - module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module ee->setObjectCache(objectCache); // FIXME: Disabled during API changes @@ -177,8 +164,7 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env) if (g_dump) module->dump(); - ee->addModule(module.get()); - module.release(); + ee->addModule(std::move(module)); listener->stateChanged(ExecState::CodeGen); entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName); if (!CHECK(entryFuncPtr)) diff --git a/evmjit/libevmjit/GasMeter.cpp b/evmjit/libevmjit/GasMeter.cpp index ffbd654e6..4cd053316 100644 --- a/evmjit/libevmjit/GasMeter.cpp +++ b/evmjit/libevmjit/GasMeter.cpp @@ -216,22 +216,12 @@ void GasMeter::countExp(llvm::Value* _exponent) // cost = ((256 - lz) + 7) / 8 // OPT: Can gas update be done in exp algorithm? - - auto t = llvm::APInt{256, 1}; - auto c = m_builder.CreateSelect(m_builder.CreateICmpUGE(_exponent, Constant::get(t)), m_builder.getInt64(1), m_builder.getInt64(0)); - for (auto i = 2; i <= 32; ++i) - { - t <<= 8; - c = m_builder.CreateSelect(m_builder.CreateICmpUGE(_exponent, Constant::get(t)), m_builder.getInt64(i), c); - } - - // FIXME: Does not work because of LLVM bug: https://llvm.org/bugs/show_bug.cgi?id=22304 -// auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); -// auto lz256 = m_builder.CreateCall2(ctlz, _exponent, m_builder.getInt1(false)); -// auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz"); -// auto sigBits = m_builder.CreateSub(m_builder.getInt64(256), lz, "sigBits"); -// auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, m_builder.getInt64(7)), m_builder.getInt64(8)); - count(m_builder.CreateNUWMul(c, m_builder.getInt64(c_expByteGas))); + auto ctlz = llvm::Intrinsic::getDeclaration(getModule(), llvm::Intrinsic::ctlz, Type::Word); + auto lz256 = m_builder.CreateCall(ctlz, {_exponent, m_builder.getInt1(false)}); + auto lz = m_builder.CreateTrunc(lz256, Type::Gas, "lz"); + auto sigBits = m_builder.CreateSub(m_builder.getInt64(256), lz, "sigBits"); + auto sigBytes = m_builder.CreateUDiv(m_builder.CreateAdd(sigBits, m_builder.getInt64(7)), m_builder.getInt64(8)); + count(m_builder.CreateNUWMul(sigBytes, m_builder.getInt64(c_expByteGas))); } void GasMeter::countSStore(Ext& _ext, llvm::Value* _index, llvm::Value* _newValue) diff --git a/evmjit/libevmjit/Optimizer.cpp b/evmjit/libevmjit/Optimizer.cpp index 84a7c3a6a..df88b4df8 100644 --- a/evmjit/libevmjit/Optimizer.cpp +++ b/evmjit/libevmjit/Optimizer.cpp @@ -1,7 +1,7 @@ #include "Optimizer.h" #include "preprocessor/llvm_includes_start.h" -#include +#include #include #include #include "preprocessor/llvm_includes_end.h" @@ -15,10 +15,10 @@ namespace jit bool optimize(llvm::Module& _module) { - auto pm = llvm::PassManager{}; - //pm.add(llvm::createFunctionInliningPass(2, 2)); // Produces invalid IR + auto pm = llvm::legacy::PassManager{}; + //pm.add(llvm::createFunctionInliningPass(2, 2)); // Problem with APInt value bigger than 64bit pm.add(llvm::createCFGSimplificationPass()); - //pm.add(llvm::createInstructionCombiningPass()); // Produces invalid runtime results + pm.add(llvm::createInstructionCombiningPass()); pm.add(llvm::createAggressiveDCEPass()); pm.add(llvm::createLowerSwitchPass()); return pm.run(_module); diff --git a/evmjit/libevmjit/RuntimeManager.cpp b/evmjit/libevmjit/RuntimeManager.cpp index dc7bc24a3..5c66a5a21 100644 --- a/evmjit/libevmjit/RuntimeManager.cpp +++ b/evmjit/libevmjit/RuntimeManager.cpp @@ -93,13 +93,13 @@ RuntimeManager::RuntimeManager(llvm::IRBuilder<>& _builder, code_iterator _codeB // Unpack data auto rtPtr = getRuntimePtr(); - m_dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 0), "data"); + m_dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(getRuntimeType(), rtPtr, 0), "data"); assert(m_dataPtr->getType() == Type::RuntimeDataPtr); - m_gasPtr = m_builder.CreateStructGEP(m_dataPtr, 0, "gas"); + m_gasPtr = m_builder.CreateStructGEP(getRuntimeDataType(), m_dataPtr, 0, "gas"); assert(m_gasPtr->getType() == Type::Gas->getPointerTo()); - m_memPtr = m_builder.CreateStructGEP(rtPtr, 2, "mem"); + m_memPtr = m_builder.CreateStructGEP(getRuntimeType(), rtPtr, 2, "mem"); assert(m_memPtr->getType() == Array::getType()->getPointerTo()); - m_envPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 1), "env"); + m_envPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(getRuntimeType(), rtPtr, 1), "env"); assert(m_envPtr->getType() == Type::EnvPtr); m_stackSize = m_builder.CreateAlloca(Type::Size, nullptr, "stackSize"); @@ -160,7 +160,7 @@ llvm::Value* RuntimeManager::getDataPtr() return m_dataPtr; auto rtPtr = getRuntimePtr(); - auto dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(rtPtr, 0), "data"); + auto dataPtr = m_builder.CreateLoad(m_builder.CreateStructGEP(getRuntimeType(), rtPtr, 0), "data"); assert(dataPtr->getType() == getRuntimeDataType()->getPointerTo()); return dataPtr; } @@ -173,7 +173,7 @@ llvm::Value* RuntimeManager::getEnvPtr() llvm::Value* RuntimeManager::getPtr(RuntimeData::Index _index) { - auto ptr = getBuilder().CreateStructGEP(getDataPtr(), _index); + auto ptr = getBuilder().CreateStructGEP(getRuntimeDataType(), getDataPtr(), _index); assert(getRuntimeDataType()->getElementType(_index)->getPointerTo() == ptr->getType()); return ptr; } diff --git a/evmjit/libevmjit/Type.h b/evmjit/libevmjit/Type.h index ffacc5407..fcca98d74 100644 --- a/evmjit/libevmjit/Type.h +++ b/evmjit/libevmjit/Type.h @@ -2,8 +2,9 @@ #include "preprocessor/llvm_includes_start.h" #include -#include -#include "preprocessor/llvm_includes_end.h" +#include +#include +#include "preprocessor/llvm_includes_end.h" // FIXME: LLVM 3.7: check if needed #include "Common.h" diff --git a/exp/CMakeLists.txt b/exp/CMakeLists.txt index bfcd0e658..823425598 100644 --- a/exp/CMakeLists.txt +++ b/exp/CMakeLists.txt @@ -5,7 +5,7 @@ aux_source_directory(. SRC_LIST) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ..) -include_directories(${LEVELDB_INCLUDE_DIRS}) +include_directories(${DB_INCLUDE_DIRS}) set(EXECUTABLE exp) diff --git a/exp/main.cpp b/exp/main.cpp index f0574fa7c..1db9b4267 100644 --- a/exp/main.cpp +++ b/exp/main.cpp @@ -88,7 +88,7 @@ int main() data.push_back(rlp(i)); h256 ret; - DEV_TIMED(triedb) + DEV_TIMED("triedb") { MemoryDB mdb; GenericTrieDB t(&mdb); @@ -99,7 +99,7 @@ int main() ret = t.root(); } cdebug << ret; - DEV_TIMED(hash256) + DEV_TIMED("hash256") ret = orderedTrieRoot(data); cdebug << ret; } diff --git a/libdevcore/CMakeLists.txt b/libdevcore/CMakeLists.txt index 4a96d7ec5..7cd236cea 100644 --- a/libdevcore/CMakeLists.txt +++ b/libdevcore/CMakeLists.txt @@ -15,6 +15,7 @@ aux_source_directory(. SRC_LIST) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) +include_directories(${DB_INCLUDE_DIRS}) set(EXECUTABLE devcore) @@ -26,6 +27,7 @@ target_link_libraries(${EXECUTABLE} ${Boost_THREAD_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${Boost_SYSTEM_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${JSONCPP_LIBRARIES}) +target_link_libraries(${EXECUTABLE} ${DB_LIBRARIES}) # transitive dependencies for windows executables if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") diff --git a/libdevcore/Common.cpp b/libdevcore/Common.cpp index 17ccae6b1..e33936102 100644 --- a/libdevcore/Common.cpp +++ b/libdevcore/Common.cpp @@ -48,9 +48,9 @@ const char* TimerChannel::name() { return EthRed " ⚡ "; } TimerHelper::~TimerHelper() { - auto e = m_t.elapsed(); - if (!m_ms || e * 1000 > m_ms) - clog(TimerChannel) << m_id << e << "s"; + auto e = std::chrono::high_resolution_clock::now() - m_t; + if (!m_ms || e > chrono::milliseconds(m_ms)) + clog(TimerChannel) << m_id << chrono::duration_cast(e).count() << "ms"; } } diff --git a/libdevcore/Common.h b/libdevcore/Common.h index c6ed25223..f1d35bbc7 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #pragma warning(push) #pragma GCC diagnostic push @@ -193,16 +193,29 @@ private: class TimerHelper { public: - TimerHelper(char const* _id, unsigned _msReportWhenGreater = 0): m_id(_id), m_ms(_msReportWhenGreater) {} + TimerHelper(std::string const& _id, unsigned _msReportWhenGreater = 0): m_t(std::chrono::high_resolution_clock::now()), m_id(_id), m_ms(_msReportWhenGreater) {} ~TimerHelper(); private: - boost::timer m_t; - char const* m_id; + std::chrono::high_resolution_clock::time_point m_t; + std::string m_id; unsigned m_ms; }; -#define DEV_TIMED(S) for (::std::pair<::dev::TimerHelper, bool> __eth_t(#S, true); __eth_t.second; __eth_t.second = false) +class Timer +{ +public: + Timer() { restart(); } + + std::chrono::high_resolution_clock::duration duration() const { return std::chrono::high_resolution_clock::now() - m_t; } + double elapsed() const { return std::chrono::duration_cast(duration()).count() / 1000000.0; } + void restart() { m_t = std::chrono::high_resolution_clock::now(); } + +private: + std::chrono::high_resolution_clock::time_point m_t; +}; + +#define DEV_TIMED(S) for (::std::pair<::dev::TimerHelper, bool> __eth_t(S, true); __eth_t.second; __eth_t.second = false) #define DEV_TIMED_SCOPE(S) ::dev::TimerHelper __eth_t(S) #if WIN32 #define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__FUNCSIG__) @@ -210,7 +223,7 @@ private: #define DEV_TIMED_FUNCTION DEV_TIMED_SCOPE(__PRETTY_FUNCTION__) #endif -#define DEV_TIMED_ABOVE(S, MS) for (::std::pair<::dev::TimerHelper, bool> __eth_t(::dev::TimerHelper(#S, MS), true); __eth_t.second; __eth_t.second = false) +#define DEV_TIMED_ABOVE(S, MS) for (::std::pair<::dev::TimerHelper, bool> __eth_t(::dev::TimerHelper(S, MS), true); __eth_t.second; __eth_t.second = false) #define DEV_TIMED_SCOPE_ABOVE(S, MS) ::dev::TimerHelper __eth_t(S, MS) #if WIN32 #define DEV_TIMED_FUNCTION_ABOVE(MS) DEV_TIMED_SCOPE_ABOVE(__FUNCSIG__, MS) diff --git a/libdevcore/CommonData.h b/libdevcore/CommonData.h index facf1479e..57360e95a 100644 --- a/libdevcore/CommonData.h +++ b/libdevcore/CommonData.h @@ -104,10 +104,10 @@ bytes asNibbles(bytesConstRef const& _s); template inline void toBigEndian(_T _val, _Out& o_out) { - for (auto i = o_out.size(); i-- != 0; _val >>= 8) + for (auto i = o_out.size(); i != 0; _val >>= 8, i--) { _T v = _val & (_T)0xff; - o_out[i] = (typename _Out::value_type)(uint8_t)v; + o_out[i - 1] = (typename _Out::value_type)(uint8_t)v; } } diff --git a/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp index cfe7b8a6b..055b645ed 100644 --- a/libdevcore/CommonIO.cpp +++ b/libdevcore/CommonIO.cpp @@ -98,9 +98,9 @@ string dev::contentsString(string const& _file) void dev::writeFile(std::string const& _file, bytesConstRef _data, bool _writeDeleteRename) { + namespace fs = boost::filesystem; if (_writeDeleteRename) { - namespace fs = boost::filesystem; fs::path tempPath = fs::unique_path(_file + "-%%%%%%"); writeFile(tempPath.string(), _data, false); // will delete _file if it exists @@ -108,10 +108,14 @@ void dev::writeFile(std::string const& _file, bytesConstRef _data, bool _writeDe } else { + // create directory if not existent + fs::path p(_file); + fs::create_directories(p.parent_path()); + ofstream s(_file, ios::trunc | ios::binary); s.write(reinterpret_cast(_data.data()), _data.size()); if (!s) - BOOST_THROW_EXCEPTION(FileError()); + BOOST_THROW_EXCEPTION(FileError() << errinfo_comment("Could not write to file: " + _file)); } } diff --git a/libdevcore/FixedHash.h b/libdevcore/FixedHash.h index 922a6ec30..c7c551c2b 100644 --- a/libdevcore/FixedHash.h +++ b/libdevcore/FixedHash.h @@ -113,6 +113,9 @@ public: /// @returns an abridged version of the hash as a user-readable hex string. std::string abridged() const { return toHex(ref().cropped(0, 4)) + "\342\200\246"; } + /// @returns a version of the hash as a user-readable hex string that leaves out the middle part. + std::string abridgedMiddle() const { return toHex(ref().cropped(0, 4)) + "\342\200\246" + toHex(ref().cropped(N - 4)); } + /// @returns the hash as a user-readable hex string. std::string hex() const { return toHex(ref()); } diff --git a/libdevcore/RLP.cpp b/libdevcore/RLP.cpp index 846664cfd..330893c76 100644 --- a/libdevcore/RLP.cpp +++ b/libdevcore/RLP.cpp @@ -202,9 +202,7 @@ unsigned RLP::items() const RLPStream& RLPStream::appendRaw(bytesConstRef _s, unsigned _itemCount) { - unsigned os = m_out.size(); - m_out.resize(os + _s.size()); - memcpy(m_out.data() + os, _s.data(), _s.size()); + m_out.insert(m_out.end(), _s.begin(), _s.end()); noteAppended(_itemCount); return *this; } diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h index 6e46807ab..dee438be4 100644 --- a/libdevcore/RLP.h +++ b/libdevcore/RLP.h @@ -204,9 +204,7 @@ public: { ret.reserve(itemCount()); for (auto const& i: *this) - { ret.push_back((T)i); - } } return ret; } @@ -216,15 +214,21 @@ public: { std::set ret; if (isList()) - { for (auto const& i: *this) - { ret.insert((T)i); - } - } return ret; } - + + template + std::unordered_set toUnorderedSet() const + { + std::unordered_set ret; + if (isList()) + for (auto const& i: *this) + ret.insert((T)i); + return ret; + } + template std::pair toPair() const { @@ -292,7 +296,7 @@ public: RLPs toList() const; /// @returns the data payload. Valid for all types. - bytesConstRef payload() const { auto l = length(); if (l > m_data.size()) throw BadRLP(); return m_data.cropped(payloadOffset(), l); } + bytesConstRef payload() const { auto l = length(); if (l > m_data.size()) BOOST_THROW_EXCEPTION(BadRLP()); return m_data.cropped(payloadOffset(), l); } /// @returns the theoretical size of this item. /// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work. diff --git a/libdevcore/TrieCommon.cpp b/libdevcore/TrieCommon.cpp index ff44906b1..5bf6070ee 100644 --- a/libdevcore/TrieCommon.cpp +++ b/libdevcore/TrieCommon.cpp @@ -60,7 +60,7 @@ std::string hexPrefixEncode(bytes const& _hexVector, bool _leaf, int _begin, int std::string hexPrefixEncode(bytesConstRef _data, bool _leaf, int _beginNibble, int _endNibble, unsigned _offset) { unsigned begin = _beginNibble + _offset; - unsigned end = (_endNibble < 0 ? (_data.size() * 2 - _offset) + 1 + _endNibble : _endNibble) + _offset; + unsigned end = (_endNibble < 0 ? ((int)(_data.size() * 2 - _offset) + 1) + _endNibble : _endNibble) + _offset; bool odd = (end - begin) & 1; std::string ret(1, ((_leaf ? 2 : 0) | (odd ? 1 : 0)) * 16); diff --git a/libdevcore/TrieDB.h b/libdevcore/TrieDB.h index f9d7bff5f..f35cf893c 100644 --- a/libdevcore/TrieDB.h +++ b/libdevcore/TrieDB.h @@ -21,19 +21,14 @@ #pragma once -#pragma warning(push) -#pragma warning(disable: 4100 4267) -#include -#pragma warning(pop) - #include -#include -#include -#include -#include +#include "db.h" +#include "Common.h" +#include "Log.h" +#include "Exceptions.h" +#include "SHA3.h" #include "MemoryDB.h" #include "TrieCommon.h" -namespace ldb = leveldb; namespace dev { diff --git a/libdevcore/Worker.cpp b/libdevcore/Worker.cpp index ab19b2f74..d47955753 100644 --- a/libdevcore/Worker.cpp +++ b/libdevcore/Worker.cpp @@ -65,14 +65,14 @@ void Worker::startWorking() m_state.exchange(ex); // cnote << "Waiting until not Stopped..."; - DEV_TIMED_ABOVE(Worker stopping, 100) + DEV_TIMED_ABOVE("Worker stopping", 100) while (m_state == WorkerState::Stopped) this_thread::sleep_for(chrono::milliseconds(20)); } })); // cnote << "Spawning" << m_name; } - DEV_TIMED_ABOVE(Start worker, 100) + DEV_TIMED_ABOVE("Start worker", 100) while (m_state == WorkerState::Starting) this_thread::sleep_for(chrono::microseconds(20)); } @@ -85,7 +85,7 @@ void Worker::stopWorking() WorkerState ex = WorkerState::Started; m_state.compare_exchange_strong(ex, WorkerState::Stopping); - DEV_TIMED_ABOVE(Stop worker, 100) + DEV_TIMED_ABOVE("Stop worker", 100) while (m_state != WorkerState::Stopped) this_thread::sleep_for(chrono::microseconds(20)); } @@ -99,7 +99,7 @@ void Worker::terminate() { m_state.exchange(WorkerState::Killing); - DEV_TIMED_ABOVE(Terminate worker, 100) + DEV_TIMED_ABOVE("Terminate worker", 100) m_work->join(); m_work.reset(); diff --git a/libdevcore/db.h b/libdevcore/db.h new file mode 100644 index 000000000..4d000af78 --- /dev/null +++ b/libdevcore/db.h @@ -0,0 +1,36 @@ +/* + 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 DB.h + * @author Gav Wood + * @date 2014 + */ + +#pragma once + +#pragma warning(push) +#pragma warning(disable: 4100 4267) +#if ETH_ROCKSDB || !ETH_TRUE +#include +#include +namespace ldb = rocksdb; +#else +#include +#include +namespace ldb = leveldb; +#endif +#pragma warning(pop) +#define DEV_LDB 1 diff --git a/libdevcore/vector_ref.h b/libdevcore/vector_ref.h index 98c6adb21..b05342f71 100644 --- a/libdevcore/vector_ref.h +++ b/libdevcore/vector_ref.h @@ -31,8 +31,8 @@ public: vector_ref(typename std::conditional::value, std::vector::type> const*, std::vector<_T>*>::type _data): m_data(_data->data()), m_count(_data->size()) {} /// Creates a new vector_ref pointing to the data part of a string (given as reference). vector_ref(typename std::conditional::value, std::string const&, std::string&>::type _data): m_data(reinterpret_cast<_T*>(_data.data())), m_count(_data.size() / sizeof(_T)) {} -#ifdef STORAGE_LEVELDB_INCLUDE_DB_H_ - vector_ref(leveldb::Slice const& _s): m_data(reinterpret_cast<_T*>(_s.data())), m_count(_s.size() / sizeof(_T)) {} +#if DEV_LDB + vector_ref(ldb::Slice const& _s): m_data(reinterpret_cast<_T*>(_s.data())), m_count(_s.size() / sizeof(_T)) {} #endif explicit operator bool() const { return m_data && m_count; } @@ -77,8 +77,8 @@ public: bool operator==(vector_ref<_T> const& _cmp) const { return m_data == _cmp.m_data && m_count == _cmp.m_count; } bool operator!=(vector_ref<_T> const& _cmp) const { return !operator==(_cmp); } -#ifdef STORAGE_LEVELDB_INCLUDE_DB_H_ - operator leveldb::Slice() const { return leveldb::Slice((char const*)m_data, m_count * sizeof(_T)); } +#if DEV_LDB + operator ldb::Slice() const { return ldb::Slice((char const*)m_data, m_count * sizeof(_T)); } #endif void reset() { m_data = nullptr; m_count = 0; } diff --git a/libdevcrypto/CMakeLists.txt b/libdevcrypto/CMakeLists.txt index 7df1149b0..d30aa7bc1 100644 --- a/libdevcrypto/CMakeLists.txt +++ b/libdevcrypto/CMakeLists.txt @@ -12,7 +12,7 @@ aux_source_directory(. SRC_LIST) include_directories(BEFORE ..) include_directories(${Boost_INCLUDE_DIRS}) include_directories(${CRYPTOPP_INCLUDE_DIRS}) -include_directories(${LEVELDB_INCLUDE_DIRS}) +include_directories(${DB_INCLUDE_DIRS}) set(EXECUTABLE devcrypto) @@ -20,7 +20,7 @@ file(GLOB HEADERS "*.h") add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) target_link_libraries(${EXECUTABLE} ${Boost_FILESYSTEM_LIBRARIES}) -target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES}) +target_link_libraries(${EXECUTABLE} ${DB_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${CRYPTOPP_LIBRARIES}) target_link_libraries(${EXECUTABLE} scrypt) target_link_libraries(${EXECUTABLE} devcore) diff --git a/libdevcrypto/OverlayDB.cpp b/libdevcrypto/OverlayDB.cpp index a6aa684f2..730d71b4d 100644 --- a/libdevcrypto/OverlayDB.cpp +++ b/libdevcrypto/OverlayDB.cpp @@ -20,8 +20,7 @@ */ #include -#include -#include +#include #include #include "OverlayDB.h" using namespace std; diff --git a/libdevcrypto/OverlayDB.h b/libdevcrypto/OverlayDB.h index b37d2c11b..83618d8a3 100644 --- a/libdevcrypto/OverlayDB.h +++ b/libdevcrypto/OverlayDB.h @@ -21,16 +21,11 @@ #pragma once -#pragma warning(push) -#pragma warning(disable: 4100 4267) -#include -#pragma warning(pop) - #include +#include #include #include #include -namespace ldb = leveldb; namespace dev { diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 315f29685..79024e2ad 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -64,7 +65,7 @@ static void addDefinition(string& _source, char const* _id, unsigned _value) ethash_cl_miner::search_hook::~search_hook() {} ethash_cl_miner::ethash_cl_miner() -: m_opencl_1_1() +: m_openclOnePointOne() { } @@ -252,7 +253,7 @@ void ethash_cl_miner::finish() bool ethash_cl_miner::init( uint8_t const* _dag, uint64_t _dagSize, - unsigned workgroup_size, + unsigned _workgroupSize, unsigned _platformId, unsigned _deviceId ) @@ -291,23 +292,23 @@ bool ethash_cl_miner::init( return false; } if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0) - m_opencl_1_1 = true; + m_openclOnePointOne = true; // create context 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 - m_workgroup_size = ((workgroup_size + 7) / 8) * 8; + m_workgroupSize = ((_workgroupSize + 7) / 8) * 8; // 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 string code(ETHASH_CL_MINER_KERNEL, ETHASH_CL_MINER_KERNEL + ETHASH_CL_MINER_KERNEL_SIZE); - addDefinition(code, "GROUP_SIZE", m_workgroup_size); + addDefinition(code, "GROUP_SIZE", m_workgroupSize); addDefinition(code, "DAG_SIZE", (unsigned)(_dagSize / ETHASH_MIX_BYTES)); addDefinition(code, "ACCESSES", ETHASH_ACCESSES); - addDefinition(code, "MAX_OUTPUTS", c_max_search_results); + addDefinition(code, "MAX_OUTPUTS", c_maxSearchResults); //debugf("%s", code.c_str()); // create miner OpenCL program @@ -330,7 +331,7 @@ bool ethash_cl_miner::init( // create buffer for dag try { - m_dagChunksNum = 1; + m_dagChunksCount = 1; m_dagChunks.push_back(cl::Buffer(m_context, CL_MEM_READ_ONLY, _dagSize)); ETHCL_LOG("Created one big buffer for the DAG"); } @@ -346,8 +347,8 @@ bool ethash_cl_miner::init( << result << ". Trying to allocate 4 chunks." ); // The OpenCL kernel has a hard coded number of 4 chunks at the moment - m_dagChunksNum = 4; - for (unsigned i = 0; i < m_dagChunksNum; i++) + m_dagChunksCount = 4; + for (unsigned i = 0; i < m_dagChunksCount; 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); @@ -359,24 +360,24 @@ bool ethash_cl_miner::init( } } - if (m_dagChunksNum == 1) + if (m_dagChunksCount == 1) { ETHCL_LOG("Loading single big chunk kernels"); - m_hash_kernel = cl::Kernel(program, "ethash_hash"); - m_search_kernel = cl::Kernel(program, "ethash_search"); + m_hashKernel = cl::Kernel(program, "ethash_hash"); + m_searchKernel = cl::Kernel(program, "ethash_search"); } else { ETHCL_LOG("Loading chunk kernels"); - m_hash_kernel = cl::Kernel(program, "ethash_hash_chunks"); - m_search_kernel = cl::Kernel(program, "ethash_search_chunks"); + m_hashKernel = cl::Kernel(program, "ethash_hash_chunks"); + m_searchKernel = cl::Kernel(program, "ethash_search_chunks"); } // create buffer for header ETHCL_LOG("Creating buffer for header."); m_header = cl::Buffer(m_context, CL_MEM_READ_ONLY, 32); - if (m_dagChunksNum == 1) + if (m_dagChunksCount == 1) { ETHCL_LOG("Mapping one big chunk."); m_queue.enqueueWriteBuffer(m_dagChunks[0], CL_TRUE, 0, _dagSize, _dag); @@ -385,12 +386,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 < m_dagChunksNum; i++) + for (unsigned i = 0; i < m_dagChunksCount; 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); + dag_ptr[i] = m_queue.enqueueMapBuffer(m_dagChunks[i], true, m_openclOnePointOne ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, (i == 3) ? (_dagSize - 3 * ((_dagSize >> 9) << 7)) : (_dagSize >> 9) << 7); } - for (unsigned i = 0; i < m_dagChunksNum; i++) + for (unsigned i = 0; i < m_dagChunksCount; 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]); @@ -398,11 +399,11 @@ bool ethash_cl_miner::init( } // create mining buffers - for (unsigned i = 0; i != c_num_buffers; ++i) + for (unsigned i = 0; i != c_bufferCount; ++i) { ETHCL_LOG("Creating mining buffer " << i); - m_hash_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY | (!m_opencl_1_1 ? CL_MEM_HOST_READ_ONLY : 0), 32 * c_hash_batch_size); - m_search_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_max_search_results + 1) * sizeof(uint32_t)); + m_hashBuffer[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY | (!m_openclOnePointOne ? CL_MEM_HOST_READ_ONLY : 0), 32 * c_hashBatchSize); + m_searchBuffer[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_maxSearchResults + 1) * sizeof(uint32_t)); } } catch (cl::Error const& err) @@ -413,7 +414,7 @@ bool ethash_cl_miner::init( return true; } -void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook& hook) +void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook& hook, unsigned _msPerBatch) { try { @@ -429,8 +430,8 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook // update header constant buffer m_queue.enqueueWriteBuffer(m_header, false, 0, 32, header); - for (unsigned i = 0; i != c_num_buffers; ++i) - m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero); + for (unsigned i = 0; i != c_bufferCount; ++i) + m_queue.enqueueWriteBuffer(m_searchBuffer[i], false, 0, 4, &c_zero); #if CL_VERSION_1_2 && 0 cl::Event pre_return_event; @@ -441,53 +442,59 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook m_queue.finish(); unsigned argPos = 2; - m_search_kernel.setArg(1, m_header); - for (unsigned i = 0; i < m_dagChunksNum; ++i, ++argPos) - m_search_kernel.setArg(argPos, m_dagChunks[i]); + m_searchKernel.setArg(1, m_header); + for (unsigned i = 0; i < m_dagChunksCount; ++i, ++argPos) + m_searchKernel.setArg(argPos, m_dagChunks[i]); // pass these to stop the compiler unrolling the loops - m_search_kernel.setArg(argPos + 1, target); - m_search_kernel.setArg(argPos + 2, ~0u); + m_searchKernel.setArg(argPos + 1, target); + m_searchKernel.setArg(argPos + 2, ~0u); unsigned buf = 0; random_device engine; uint64_t start_nonce = uniform_int_distribution()(engine); - for (;; start_nonce += c_search_batch_size) + for (;; start_nonce += m_batchSize) { // supply output buffer to kernel - m_search_kernel.setArg(0, m_search_buf[buf]); - if (m_dagChunksNum == 1) - m_search_kernel.setArg(3, start_nonce); + m_searchKernel.setArg(0, m_searchBuffer[buf]); + if (m_dagChunksCount == 1) + m_searchKernel.setArg(3, start_nonce); else - m_search_kernel.setArg(6, start_nonce); + m_searchKernel.setArg(6, start_nonce); // execute it! - m_queue.enqueueNDRangeKernel(m_search_kernel, cl::NullRange, c_search_batch_size, m_workgroup_size); + boost::timer t; + m_queue.enqueueNDRangeKernel(m_searchKernel, cl::NullRange, m_batchSize, m_workgroupSize); + unsigned ms = t.elapsed() * 1000; + if (ms > _msPerBatch * 1.1) + m_batchSize = max(128, m_batchSize * 9 / 10); + else if (ms < _msPerBatch * 0.9) + m_batchSize = m_batchSize * 10 / 9; pending.push({ start_nonce, buf }); - buf = (buf + 1) % c_num_buffers; + buf = (buf + 1) % c_bufferCount; // read results - if (pending.size() == c_num_buffers) + if (pending.size() == c_bufferCount) { pending_batch const& batch = pending.front(); // 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 = min(results[0], c_max_search_results); + uint32_t* results = (uint32_t*)m_queue.enqueueMapBuffer(m_searchBuffer[batch.buf], true, CL_MAP_READ, 0, (1 + c_maxSearchResults) * sizeof(uint32_t)); + unsigned num_found = min(results[0], c_maxSearchResults); - uint64_t nonces[c_max_search_results]; + uint64_t nonces[c_maxSearchResults]; for (unsigned i = 0; i != num_found; ++i) nonces[i] = batch.start_nonce + results[i + 1]; - m_queue.enqueueUnmapMemObject(m_search_buf[batch.buf], results); + m_queue.enqueueUnmapMemObject(m_searchBuffer[batch.buf], results); bool exit = num_found && hook.found(nonces, num_found); - exit |= hook.searched(batch.start_nonce, c_search_batch_size); // always report searched before exit + exit |= hook.searched(batch.start_nonce, m_batchSize); // always report searched before exit if (exit) break; // reset search buffer if we're still going if (num_found) - m_queue.enqueueWriteBuffer(m_search_buf[batch.buf], true, 0, 4, &c_zero); + m_queue.enqueueWriteBuffer(m_searchBuffer[batch.buf], true, 0, 4, &c_zero); pending.pop(); } diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index f36082a5a..996453c00 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -19,6 +19,9 @@ class ethash_cl_miner { +private: + enum { c_maxSearchResults = 63, c_bufferCount = 2, c_hashBatchSize = 1024, c_searchBatchSize = 1024 * 16 }; + public: struct search_hook { @@ -29,7 +32,6 @@ public: virtual bool searched(uint64_t start_nonce, uint32_t count) = 0; }; -public: ethash_cl_miner(); ~ethash_cl_miner(); @@ -50,33 +52,32 @@ public: bool init( uint8_t const* _dag, uint64_t _dagSize, - unsigned workgroup_size = 64, + unsigned _workgroupSize = 64, unsigned _platformId = 0, unsigned _deviceId = 0 ); void finish(); - void search(uint8_t const* header, uint64_t target, search_hook& hook); + void search(uint8_t const* _header, uint64_t _target, search_hook& _hook, unsigned _msPerBatch = 100); - void hash_chunk(uint8_t* ret, uint8_t const* header, uint64_t nonce, unsigned count); - void search_chunk(uint8_t const* header, uint64_t target, search_hook& hook); + void hash_chunk(uint8_t* _ret, uint8_t const* _header, uint64_t _nonce, unsigned _count); + 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 int m_dagChunksNum; + cl::Kernel m_hashKernel; + cl::Kernel m_searchKernel; + unsigned int m_dagChunksCount; 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; + cl::Buffer m_hashBuffer[c_bufferCount]; + cl::Buffer m_searchBuffer[c_bufferCount]; + unsigned m_workgroupSize; + unsigned m_batchSize = c_searchBatchSize; + bool m_openclOnePointOne; /// Allow CPU to appear as an OpenCL device or not. Default is false static bool s_allowCPU; diff --git a/libethcore/BlockInfo.cpp b/libethcore/BlockInfo.cpp index 69da52b09..fec5b4678 100644 --- a/libethcore/BlockInfo.cpp +++ b/libethcore/BlockInfo.cpp @@ -122,7 +122,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const try { if (_header.itemCount() != 15) - throw InvalidBlockHeaderItemCount(); + BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount()); parentHash = _header[field = 0].toHash(RLP::VeryStrict); sha3Uncles = _header[field = 1].toHash(RLP::VeryStrict); coinbaseAddress = _header[field = 2].toHash
(RLP::VeryStrict); @@ -146,7 +146,7 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s, h256 const } if (number > ~(unsigned)0) - throw InvalidNumber(); + BOOST_THROW_EXCEPTION(InvalidNumber()); // check it hashes according to proof of work or that it's the genesis block. if (_s == CheckEverything && parentHash && !ProofOfWork::verify(*this)) diff --git a/libethcore/Common.h b/libethcore/Common.h index 19ca600b9..25a6a8e1d 100644 --- a/libethcore/Common.h +++ b/libethcore/Common.h @@ -97,6 +97,12 @@ enum class RelativeBlock: BlockNumber Pending = PendingBlock }; +struct ImportRoute +{ + h256s deadBlocks; + h256s liveBlocks; +}; + enum class ImportResult { Success = 0, diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index b277e3c1c..70908ee44 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -225,26 +225,58 @@ std::string Ethash::CPUMiner::platformInfo() #if ETH_ETHASHCL || !ETH_TRUE +using UniqueGuard = std::unique_lock; + +template +class Notified +{ +public: + Notified() {} + Notified(N const& _v): m_value(_v) {} + Notified(Notified const&) = delete; + Notified& operator=(N const& _v) { UniqueGuard l(m_mutex); m_value = _v; m_cv.notify_all(); return *this; } + + operator N() const { UniqueGuard l(m_mutex); return m_value; } + + void wait() const { UniqueGuard l(m_mutex); m_cv.wait(l); } + void wait(N const& _v) const { UniqueGuard l(m_mutex); m_cv.wait(l, [&](){return m_value == _v;}); } + template void wait(F const& _f) const { UniqueGuard l(m_mutex); m_cv.wait(l, _f); } + +private: + mutable Mutex m_mutex; + mutable std::condition_variable m_cv; + N m_value; +}; + class EthashCLHook: public ethash_cl_miner::search_hook { public: EthashCLHook(Ethash::GPUMiner* _owner): m_owner(_owner) {} + EthashCLHook(EthashCLHook const&) = delete; void abort() { - Guard l(x_all); - if (m_aborted) - return; + { + UniqueGuard l(x_all); + if (m_aborted) + return; // cdebug << "Attempting to abort"; - m_abort = true; - for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout) - std::this_thread::sleep_for(chrono::milliseconds(30)); + + m_abort = true; + } + // m_abort is true so now searched()/found() will return true to abort the search. + // we hang around on this thread waiting for them to point out that they have aborted since + // otherwise we may end up deleting this object prior to searched()/found() being called. + m_aborted.wait(true); +// for (unsigned timeout = 0; timeout < 100 && !m_aborted; ++timeout) +// std::this_thread::sleep_for(chrono::milliseconds(30)); // if (!m_aborted) // cwarn << "Couldn't abort. Abandoning OpenCL process."; } void reset() { + UniqueGuard l(x_all); m_aborted = m_abort = false; } @@ -253,27 +285,19 @@ protected: { // dev::operator <<(std::cerr << "Found nonces: ", vector(_nonces, _nonces + _count)) << std::endl; for (uint32_t i = 0; i < _count; ++i) - { if (m_owner->report(_nonces[i])) - { - m_aborted = true; - return true; - } - } + return (m_aborted = true); return m_owner->shouldStop(); } virtual bool searched(uint64_t _startNonce, uint32_t _count) override { - Guard l(x_all); + UniqueGuard l(x_all); // std::cerr << "Searched " << _count << " from " << _startNonce << std::endl; m_owner->accumulateHashes(_count); m_last = _startNonce + _count; if (m_abort || m_owner->shouldStop()) - { - m_aborted = true; - return true; - } + return (m_aborted = true); return false; } @@ -281,7 +305,7 @@ private: Mutex x_all; uint64_t m_last; bool m_abort = false; - bool m_aborted = true; + Notified m_aborted = {true}; Ethash::GPUMiner* m_owner = nullptr; }; diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 51a606ff8..efb6066f7 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -49,6 +49,13 @@ EthashAux::~EthashAux() { } +EthashAux* EthashAux::get() +{ + static std::once_flag flag; + std::call_once(flag, []{s_this = new EthashAux();}); + return s_this; +} + uint64_t EthashAux::cacheSize(BlockInfo const& _header) { return ethash_get_cachesize((uint64_t)_header.number); @@ -112,9 +119,11 @@ void EthashAux::killCache(h256 const& _s) EthashAux::LightType EthashAux::light(h256 const& _seedHash) { - ReadGuard l(get()->x_lights); - LightType ret = get()->m_lights[_seedHash]; - return ret ? ret : (get()->m_lights[_seedHash] = make_shared(_seedHash)); + UpgradableGuard l(get()->x_lights); + if (get()->m_lights.count(_seedHash)) + return get()->m_lights.at(_seedHash); + UpgradeGuard l2(l); + return (get()->m_lights[_seedHash] = make_shared(_seedHash)); } EthashAux::LightAllocation::LightAllocation(h256 const& _seedHash) diff --git a/libethcore/EthashAux.h b/libethcore/EthashAux.h index 47180bfd2..d5bd60d44 100644 --- a/libethcore/EthashAux.h +++ b/libethcore/EthashAux.h @@ -38,7 +38,7 @@ class EthashAux public: ~EthashAux(); - static EthashAux* get() { if (!s_this) s_this = new EthashAux(); return s_this; } + static EthashAux* get(); struct LightAllocation { diff --git a/libethcore/Exceptions.h b/libethcore/Exceptions.h index b411ea416..0ac9df5b2 100644 --- a/libethcore/Exceptions.h +++ b/libethcore/Exceptions.h @@ -51,6 +51,7 @@ DEV_SIMPLE_EXCEPTION(FeeTooSmall); DEV_SIMPLE_EXCEPTION(TooMuchGasUsed); DEV_SIMPLE_EXCEPTION(ExtraDataTooBig); DEV_SIMPLE_EXCEPTION(InvalidSignature); +DEV_SIMPLE_EXCEPTION(InvalidTransactionFormat); DEV_SIMPLE_EXCEPTION(InvalidBlockFormat); DEV_SIMPLE_EXCEPTION(InvalidUnclesHash); DEV_SIMPLE_EXCEPTION(TooManyUncles); diff --git a/libethcore/Farm.h b/libethcore/Farm.h index 9acb375ad..ba98becca 100644 --- a/libethcore/Farm.h +++ b/libethcore/Farm.h @@ -68,6 +68,7 @@ public: void setWork(WorkPackage const& _wp) { WriteGuard l(x_minerWork); + cdebug << "Farm::setWork()"; if (_wp.headerHash == m_work.headerHash) return; m_work = _wp; @@ -175,6 +176,7 @@ private: bool start() { WriteGuard l(x_minerWork); + cdebug << "start()"; if (!m_miners.empty() && !!std::dynamic_pointer_cast(m_miners[0])) return true; m_miners.clear(); diff --git a/libethcore/ICAP.cpp b/libethcore/ICAP.cpp index 158c297f8..12e8aed56 100644 --- a/libethcore/ICAP.cpp +++ b/libethcore/ICAP.cpp @@ -71,7 +71,7 @@ ICAP ICAP::decoded(std::string const& _encoded) std::string data; std::tie(country, data) = fromIBAN(_encoded); if (country != "XE") - throw InvalidICAP(); + BOOST_THROW_EXCEPTION(InvalidICAP()); if (data.size() == 30) { ret.m_type = Direct; @@ -88,10 +88,10 @@ ICAP ICAP::decoded(std::string const& _encoded) ret.m_client = data.substr(7); } else - throw InvalidICAP(); + BOOST_THROW_EXCEPTION(InvalidICAP()); } else - throw InvalidICAP(); + BOOST_THROW_EXCEPTION(InvalidICAP()); return ret; } @@ -101,7 +101,7 @@ std::string ICAP::encoded() const if (m_type == Direct) { if (!!m_direct[0]) - throw InvalidICAP(); + BOOST_THROW_EXCEPTION(InvalidICAP()); std::string d = toBase36(m_direct); while (d.size() < 30) d = "0" + d; @@ -118,11 +118,11 @@ std::string ICAP::encoded() const m_institution.size() != 4 || m_client.size() != 9 ) - throw InvalidICAP(); + BOOST_THROW_EXCEPTION(InvalidICAP()); return iban("XE", m_asset + m_institution + m_client); } else - throw InvalidICAP(); + BOOST_THROW_EXCEPTION(InvalidICAP()); } pair ICAP::lookup(std::function const& _call, Address const& _reg) const @@ -149,9 +149,9 @@ pair ICAP::lookup(std::function const& _c else if (m_institution[0] != 'X') return make_pair(resolve(m_institution + "/" + m_client), bytes()); else - throw InterfaceNotSupported("ICAP::lookup(), bad institution"); + BOOST_THROW_EXCEPTION(InterfaceNotSupported("ICAP::lookup(), bad institution")); } - throw InterfaceNotSupported("ICAP::lookup(), bad asset"); + BOOST_THROW_EXCEPTION(InterfaceNotSupported("ICAP::lookup(), bad asset")); } } diff --git a/libethcore/Miner.h b/libethcore/Miner.h index 11b9ae140..415da9878 100644 --- a/libethcore/Miner.h +++ b/libethcore/Miner.h @@ -107,9 +107,9 @@ public: } if (!!_work) { - DEV_TIMED_ABOVE(pause, 250) + DEV_TIMED_ABOVE("pause", 250) pause(); - DEV_TIMED_ABOVE(kickOff, 250) + DEV_TIMED_ABOVE("kickOff", 250) kickOff(); } else if (!_work && !!old) diff --git a/libethereum/BlockChain.cpp b/libethereum/BlockChain.cpp index b2da42e71..7abf9316e 100644 --- a/libethereum/BlockChain.cpp +++ b/libethereum/BlockChain.cpp @@ -24,8 +24,6 @@ #if ETH_PROFILING_GPERF #include #endif -#include -#include #include #include #include @@ -151,6 +149,7 @@ void BlockChain::open(std::string const& _path, WithExisting _we) ldb::Options o; o.create_if_missing = true; + o.max_open_files = 256; ldb::DB::Open(o, path + "/blocks", &m_blocksDB); ldb::DB::Open(o, path + "/details", &m_extrasDB); if (!m_blocksDB || !m_extrasDB) @@ -241,7 +240,7 @@ void BlockChain::rebuild(std::string const& _path, std::functionPut(m_writeOptions, toSlice(m_lastBlockHash, ExtraDetails), (ldb::Slice)dev::ref(m_details[m_lastBlockHash].rlp())); h256 lastHash = m_lastBlockHash; - boost::timer t; + Timer t; for (unsigned d = 1; d < originalNumber; ++d) { if (!(d % 1000)) @@ -305,7 +304,7 @@ LastHashes BlockChain::lastHashes(unsigned _n) const return m_lastLastHashes; } -tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max) +tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max) { // _bq.tick(*this); @@ -315,6 +314,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _sta h256s fresh; h256s dead; h256s badBlocks; + unsigned count = 0; for (VerifiedBlock const& block: blocks) if (!badBlocks.empty()) badBlocks.push_back(block.verified.info.hash()); @@ -324,10 +324,11 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _sta { // Nonce & uncle nonces already verified in verification thread at this point. ImportRoute r; - DEV_TIMED_ABOVE(Block import, 500) + DEV_TIMED_ABOVE("Block import", 500) r = import(block.verified, _stateDB, ImportRequirements::Default & ~ImportRequirements::ValidNonce & ~ImportRequirements::CheckUncles); fresh += r.liveBlocks; dead += r.deadBlocks; + ++count; } catch (dev::eth::UnknownParent) { @@ -353,7 +354,7 @@ tuple BlockChain::sync(BlockQueue& _bq, OverlayDB const& _sta badBlocks.push_back(block.verified.info.hash()); } } - return make_tuple(ImportRoute{dead, fresh}, _bq.doneDrain(badBlocks)); + return make_tuple(ImportRoute{dead, fresh}, _bq.doneDrain(badBlocks), count); } pair BlockChain::attemptImport(bytes const& _block, OverlayDB const& _stateDB, ImportRequirements::value _ir) noexcept @@ -391,12 +392,13 @@ ImportRoute BlockChain::import(bytes const& _block, OverlayDB const& _db, Import try #endif { - block = verifyBlock(_block, m_onBad); + block = verifyBlock(_block, m_onBad, _ir); } #if ETH_CATCH catch (Exception& ex) { // clog(BlockChainNote) << " Malformed block: " << diagnostic_information(ex); + ex << errinfo_phase(2); ex << errinfo_now(time(0)); ex << errinfo_block(_block); throw; @@ -411,13 +413,13 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& //@tidy This is a behemoth of a method - could do to be split into a few smaller ones. #if ETH_TIMED_IMPORTS - boost::timer total; + Timer total; double preliminaryChecks; double enactment; double collation; double writing; double checkBest; - boost::timer t; + Timer t; #endif // Check block doesn't already exist first! @@ -469,6 +471,9 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& h256 newLastBlockHash = currentHash(); unsigned newLastBlockNumber = number(); + BlockLogBlooms blb; + BlockReceipts br; + u256 td; #if ETH_CATCH try @@ -479,8 +484,6 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& State s(_db); auto tdIncrease = s.enactOn(_block, *this, _ir); - BlockLogBlooms blb; - BlockReceipts br; for (unsigned i = 0; i < s.pending().size(); ++i) { blb.blooms.push_back(s.receipt(i).bloom()); @@ -674,15 +677,17 @@ ImportRoute BlockChain::import(VerifiedBlockRef const& _block, OverlayDB const& #if ETH_TIMED_IMPORTS checkBest = t.elapsed(); - if (total.elapsed() > 1.0) + if (total.elapsed() > 0.5) { - cnote << "SLOW IMPORT:" << _block.info.hash(); + cnote << "SLOW IMPORT:" << _block.info.hash() << " #" << _block.info.number; cnote << " Import took:" << total.elapsed(); cnote << " preliminaryChecks:" << preliminaryChecks; cnote << " enactment:" << enactment; cnote << " collation:" << collation; cnote << " writing:" << writing; cnote << " checkBest:" << checkBest; + cnote << " " << _block.transactions.size() << " transactions"; + cnote << " " << _block.info.gasUsed << " gas used"; } #endif @@ -1080,6 +1085,7 @@ VerifiedBlockRef BlockChain::verifyBlock(bytes const& _block, function -#pragma warning(pop) - #include #include #include #include +#include #include #include #include @@ -41,7 +37,6 @@ #include "Transaction.h" #include "BlockQueue.h" #include "VerifiedBlock.h" -namespace ldb = leveldb; namespace std { @@ -81,12 +76,6 @@ using BlocksHash = std::unordered_map; using TransactionHashes = h256s; using UncleHashes = h256s; -struct ImportRoute -{ - h256s deadBlocks; - h256s liveBlocks; -}; - enum { ExtraDetails = 0, ExtraBlockHash, @@ -117,7 +106,7 @@ public: /// Sync the chain with any incoming blocks. All blocks should, if processed in order. /// @returns fresh blocks, dead blocks and true iff there are additional blocks to be processed waiting. - std::tuple sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max); + std::tuple sync(BlockQueue& _bq, OverlayDB const& _stateDB, unsigned _max); /// Attempt to import the given block directly into the CanonBlockChain and sync with the state DB. /// @returns the block hashes of any blocks that came into/went out of the canonical block chain. diff --git a/libethereum/BlockChainSync.cpp b/libethereum/BlockChainSync.cpp index c3ea67e22..da341867a 100644 --- a/libethereum/BlockChainSync.cpp +++ b/libethereum/BlockChainSync.cpp @@ -68,13 +68,10 @@ DownloadMan& BlockChainSync::downloadMan() void BlockChainSync::abortSync() { - DEV_INVARIANT_CHECK; - host().foreachPeer([this](EthereumPeer* _p) { onPeerAborting(_p); return true; }); downloadMan().resetToChain(h256s()); - DEV_INVARIANT_CHECK; } -void BlockChainSync::onPeerStatus(EthereumPeer* _peer) +void BlockChainSync::onPeerStatus(std::shared_ptr _peer) { RecursiveGuard l(x_sync); DEV_INVARIANT_CHECK; @@ -111,7 +108,7 @@ unsigned BlockChainSync::estimatedHashes() const return blockCount; } -void BlockChainSync::requestBlocks(EthereumPeer* _peer) +void BlockChainSync::requestBlocks(std::shared_ptr _peer) { if (host().bq().knownFull()) { @@ -130,7 +127,14 @@ void BlockChainSync::requestBlocks(EthereumPeer* _peer) } } -void BlockChainSync::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) +void BlockChainSync::logNewBlock(h256 const& _h) +{ + if (m_state == SyncState::NewBlocks) + clog(NetNote) << "NewBlock: " << _h; + m_knownNewHashes.erase(_h); +} + +void BlockChainSync::onPeerBlocks(std::shared_ptr _peer, RLP const& _r) { RecursiveGuard l(x_sync); DEV_INVARIANT_CHECK; @@ -138,7 +142,7 @@ void BlockChainSync::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) clog(NetMessageSummary) << "Blocks (" << dec << itemCount << "entries)" << (itemCount ? "" : ": NoMoreBlocks"); _peer->setIdle(); - if (m_state != SyncState::Blocks && m_state != SyncState::NewBlocks) + if (m_state != SyncState::Blocks && m_state != SyncState::NewBlocks && m_state != SyncState::Waiting) clog(NetWarn) << "Unexpected Blocks received!"; if (m_state == SyncState::Waiting) { @@ -173,14 +177,17 @@ void BlockChainSync::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) { case ImportResult::Success: success++; + logNewBlock(h); break; case ImportResult::Malformed: case ImportResult::BadChain: + logNewBlock(h); _peer->disable("Malformed block received."); return; case ImportResult::FutureTimeKnown: + logNewBlock(h); future++; break; case ImportResult::AlreadyInChain: @@ -194,6 +201,7 @@ void BlockChainSync::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) case ImportResult::UnknownParent: { unknown++; + logNewBlock(h); if (m_state == SyncState::NewBlocks) { BlockInfo bi; @@ -241,12 +249,11 @@ void BlockChainSync::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) DEV_INVARIANT_CHECK; } -void BlockChainSync::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) +void BlockChainSync::onPeerNewBlock(std::shared_ptr _peer, RLP const& _r) { DEV_INVARIANT_CHECK; RecursiveGuard l(x_sync); auto h = BlockInfo::headerHash(_r[0].data()); - clog(NetMessageSummary) << "NewBlock: " << h; if (_r.itemCount() != 2) _peer->disable("NewBlock without 2 data fields."); @@ -256,6 +263,7 @@ void BlockChainSync::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) { case ImportResult::Success: _peer->addRating(100); + logNewBlock(h); break; case ImportResult::FutureTimeKnown: //TODO: Rating dependent on how far in future it is. @@ -263,6 +271,7 @@ void BlockChainSync::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) case ImportResult::Malformed: case ImportResult::BadChain: + logNewBlock(h); _peer->disable("Malformed block received."); return; @@ -272,6 +281,7 @@ void BlockChainSync::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) case ImportResult::FutureTimeUnknown: case ImportResult::UnknownParent: + logNewBlock(h); clog(NetMessageSummary) << "Received block with no known parent. Resyncing..."; resetSyncFor(_peer, h, _r[1].toInt()); break; @@ -309,17 +319,17 @@ SyncStatus PV60Sync::status() const return res; } -void PV60Sync::setState(EthereumPeer* _peer, SyncState _s, bool _isSyncing, bool _needHelp) +void PV60Sync::setState(std::shared_ptr _peer, SyncState _s, bool _isSyncing, bool _needHelp) { bool changedState = (m_state != _s); m_state = _s; - if (_isSyncing != (m_syncer == _peer) || (_isSyncing && changedState)) + if (_isSyncing != (m_syncer.lock() == _peer) || (_isSyncing && changedState)) changeSyncer(_isSyncing ? _peer : nullptr, _needHelp); else if (_s == SyncState::Idle) changeSyncer(nullptr, _needHelp); - assert(!!m_syncer || _s == SyncState::Idle); + assert(isSyncing() || _s == SyncState::Idle); } void PV60Sync::resetSync() @@ -335,32 +345,33 @@ void PV60Sync::restartSync() resetSync(); host().bq().clear(); if (isSyncing()) - transition(m_syncer, SyncState::Idle); + transition(m_syncer.lock(), SyncState::Idle); } void PV60Sync::completeSync() { if (isSyncing()) - transition(m_syncer, SyncState::Idle); + transition(m_syncer.lock(), SyncState::Idle); } void PV60Sync::pauseSync() { if (isSyncing()) - setState(m_syncer, SyncState::Waiting, true); + setState(m_syncer.lock(), SyncState::Waiting, true); } void PV60Sync::continueSync() { - transition(m_syncer, SyncState::Blocks); + if (isSyncing()) + transition(m_syncer.lock(), SyncState::Blocks); } -void PV60Sync::onNewPeer(EthereumPeer* _peer) +void PV60Sync::onNewPeer(std::shared_ptr _peer) { setNeedsSyncing(_peer, _peer->m_latestHash, _peer->m_totalDifficulty); } -void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _needHelp) +void PV60Sync::transition(std::shared_ptr _peer, SyncState _s, bool _force, bool _needHelp) { clog(NetMessageSummary) << "Transition!" << EthereumHost::stateName(_s) << "from" << EthereumHost::stateName(m_state) << ", " << (isSyncing(_peer) ? "syncing" : "holding") << (needsSyncing(_peer) ? "& needed" : ""); @@ -404,13 +415,13 @@ void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _ } if (shouldGrabBlocks(_peer)) { - clog(NetNote) << "Difficulty of hashchain HIGHER. Grabbing" << m_syncingNeededBlocks.size() << "blocks [latest now" << m_syncingLatestHash << ", was" << host().latestBlockSent() << "]"; + clog(NetMessageDetail) << "Difficulty of hashchain HIGHER. Grabbing" << m_syncingNeededBlocks.size() << "blocks [latest now" << m_syncingLatestHash << ", was" << host().latestBlockSent() << "]"; downloadMan().resetToChain(m_syncingNeededBlocks); resetSync(); } else { - clog(NetNote) << "Difficulty of hashchain not HIGHER. Ignoring."; + clog(NetMessageDetail) << "Difficulty of hashchain not HIGHER. Ignoring."; resetSync(); setState(_peer, SyncState::Idle, false); return; @@ -451,10 +462,10 @@ void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _ } else if (_s == SyncState::Idle) { - host().foreachPeer([this](EthereumPeer* _p) { _p->setIdle(); return true; }); + host().foreachPeer([this](std::shared_ptr _p) { _p->setIdle(); return true; }); if (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks) { - clog(NetNote) << "Finishing blocks fetch..."; + clog(NetMessageDetail) << "Finishing blocks fetch..."; // a bit overkill given that the other nodes may yet have the needed blocks, but better to be safe than sorry. if (isSyncing(_peer)) @@ -467,7 +478,7 @@ void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _ } else if (m_state == SyncState::Hashes) { - clog(NetNote) << "Finishing hashes fetch..."; + clog(NetMessageDetail) << "Finishing hashes fetch..."; setState(_peer, SyncState::Idle, false); } // Otherwise it's fine. We don't care if it's Nothing->Nothing. @@ -478,12 +489,12 @@ void PV60Sync::transition(EthereumPeer* _peer, SyncState _s, bool _force, bool _ clog(NetWarn) << "Invalid state transition:" << EthereumHost::stateName(_s) << "from" << EthereumHost::stateName(m_state) << ", " << (isSyncing(_peer) ? "syncing" : "holding") << (needsSyncing(_peer) ? "& needed" : ""); } -void PV60Sync::resetSyncFor(EthereumPeer* _peer, h256 const& _latestHash, u256 const& _td) +void PV60Sync::resetSyncFor(std::shared_ptr _peer, h256 const& _latestHash, u256 const& _td) { setNeedsSyncing(_peer, _latestHash, _td); } -void PV60Sync::setNeedsSyncing(EthereumPeer* _peer, h256 const& _latestHash, u256 const& _td) +void PV60Sync::setNeedsSyncing(std::shared_ptr _peer, h256 const& _latestHash, u256 const& _td) { _peer->m_latestHash = _latestHash; _peer->m_totalDifficulty = _td; @@ -494,17 +505,17 @@ void PV60Sync::setNeedsSyncing(EthereumPeer* _peer, h256 const& _latestHash, u25 _peer->session()->addNote("sync", string(isSyncing(_peer) ? "ongoing" : "holding") + (needsSyncing(_peer) ? " & needed" : "")); } -bool PV60Sync::needsSyncing(EthereumPeer* _peer) const +bool PV60Sync::needsSyncing(std::shared_ptr _peer) const { return !!_peer->m_latestHash; } -bool PV60Sync::isSyncing(EthereumPeer* _peer) const +bool PV60Sync::isSyncing(std::shared_ptr _peer) const { - return m_syncer == _peer; + return m_syncer.lock() == _peer; } -bool PV60Sync::shouldGrabBlocks(EthereumPeer* _peer) const +bool PV60Sync::shouldGrabBlocks(std::shared_ptr _peer) const { auto td = _peer->m_totalDifficulty; auto lh = _peer->m_latestHash; @@ -513,7 +524,7 @@ bool PV60Sync::shouldGrabBlocks(EthereumPeer* _peer) const if (m_syncingNeededBlocks.empty()) return false; - clog(NetNote) << "Should grab blocks? " << td << "vs" << ctd << ";" << m_syncingNeededBlocks.size() << " blocks, ends" << m_syncingNeededBlocks.back(); + clog(NetMessageDetail) << "Should grab blocks? " << td << "vs" << ctd << ";" << m_syncingNeededBlocks.size() << " blocks, ends" << m_syncingNeededBlocks.back(); if (td < ctd || (td == ctd && host().chain().currentHash() == lh)) return false; @@ -521,7 +532,7 @@ bool PV60Sync::shouldGrabBlocks(EthereumPeer* _peer) const return true; } -void PV60Sync::attemptSync(EthereumPeer* _peer) +void PV60Sync::attemptSync(std::shared_ptr _peer) { if (m_state != SyncState::Idle) { @@ -556,7 +567,7 @@ void PV60Sync::attemptSync(EthereumPeer* _peer) } } -void PV60Sync::noteNeedsSyncing(EthereumPeer* _peer) +void PV60Sync::noteNeedsSyncing(std::shared_ptr _peer) { // if already downloading hash-chain, ignore. if (isSyncing()) @@ -570,7 +581,7 @@ void PV60Sync::noteNeedsSyncing(EthereumPeer* _peer) attemptSync(_peer); } -void PV60Sync::changeSyncer(EthereumPeer* _syncer, bool _needHelp) +void PV60Sync::changeSyncer(std::shared_ptr _syncer, bool _needHelp) { if (_syncer) clog(NetAllDetail) << "Changing syncer to" << _syncer->session()->socketId(); @@ -581,9 +592,9 @@ void PV60Sync::changeSyncer(EthereumPeer* _syncer, bool _needHelp) if (isSyncing()) { if (_needHelp && (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks)) - host().foreachPeer([&](EthereumPeer* _p) + host().foreachPeer([&](std::shared_ptr _p) { - clog(NetNote) << "Getting help with downloading blocks"; + clog(NetMessageDetail) << "Getting help with downloading blocks"; if (_p != _syncer && _p->m_asking == Asking::Nothing) transition(_p, m_state); return true; @@ -592,7 +603,7 @@ void PV60Sync::changeSyncer(EthereumPeer* _syncer, bool _needHelp) else { // start grabbing next hash chain if there is one. - host().foreachPeer([this](EthereumPeer* _p) + host().foreachPeer([this](std::shared_ptr _p) { attemptSync(_p); return !isSyncing(); @@ -601,24 +612,24 @@ void PV60Sync::changeSyncer(EthereumPeer* _syncer, bool _needHelp) { if (m_state != SyncState::Idle) setState(_syncer, SyncState::Idle); - clog(NetNote) << "No more peers to sync with."; + clog(NetMessageDetail) << "No more peers to sync with."; } } - assert(!!m_syncer || m_state == SyncState::Idle); + assert(isSyncing() || m_state == SyncState::Idle); } -void PV60Sync::peerDoneBlocks(EthereumPeer* _peer) +void PV60Sync::peerDoneBlocks(std::shared_ptr _peer) { noteDoneBlocks(_peer, false); } -void PV60Sync::noteDoneBlocks(EthereumPeer* _peer, bool _clemency) +void PV60Sync::noteDoneBlocks(std::shared_ptr _peer, bool _clemency) { resetNeedsSyncing(_peer); if (downloadMan().isComplete()) { // Done our chain-get. - clog(NetNote) << "Chain download complete."; + clog(NetMessageDetail) << "Chain download complete."; // 1/100th for each useful block hash. _peer->addRating(downloadMan().chainSize() / 100); downloadMan().reset(); @@ -643,7 +654,7 @@ void PV60Sync::noteDoneBlocks(EthereumPeer* _peer, bool _clemency) _peer->m_sub.doneFetch(); } -void PV60Sync::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) +void PV60Sync::onPeerHashes(std::shared_ptr _peer, h256s const& _hashes) { RecursiveGuard l(x_sync); DEV_INVARIANT_CHECK; @@ -698,11 +709,11 @@ void PV60Sync::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) DEV_INVARIANT_CHECK; } -void PV60Sync::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) +void PV60Sync::onPeerNewHashes(std::shared_ptr _peer, h256s const& _hashes) { RecursiveGuard l(x_sync); DEV_INVARIANT_CHECK; - if (isSyncing()) + if (isSyncing() && (m_state != SyncState::NewBlocks || isSyncing(_peer))) { clog(NetMessageSummary) << "Ignoring since we're already downloading."; return; @@ -734,43 +745,55 @@ void PV60Sync::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) clog(NetMessageSummary) << knowns << "knowns," << unknowns << "unknowns"; if (unknowns > 0) { - clog(NetNote) << "Not syncing and new block hash discovered: syncing without help."; - downloadMan().resetToChain(m_syncingNeededBlocks); + if (m_state == SyncState::NewBlocks) + { + clog(NetMessageDetail) << "Downloading new blocks and seeing new hashes. Trying grabbing blocks"; + _peer->requestBlocks(m_syncingNeededBlocks); + } + else + { + clog(NetMessageDetail) << "Not syncing and new block hash discovered: syncing without help."; + downloadMan().resetToChain(m_syncingNeededBlocks); + transition(_peer, SyncState::NewBlocks, false, false); + } + for (auto const& h: m_syncingNeededBlocks) + if (!m_knownNewHashes.count(h)) + { + m_knownNewHashes.insert(h); + clog(NetNote) << "NewHash: " << h; + } resetSync(); - transition(_peer, SyncState::NewBlocks, false, false); } DEV_INVARIANT_CHECK; } -void PV60Sync::abortSync(EthereumPeer* _peer) +void PV60Sync::abortSync() { // Can't check invariants here since the peers is already removed from the list and the state is not updated yet. - if (isSyncing(_peer)) - { - host().foreachPeer([this](EthereumPeer* _p) { _p->setIdle(); return true; }); - transition(_peer, SyncState::Idle, true); - } + host().foreachPeer([this](std::shared_ptr _p) { _p->setIdle(); return true; }); + setState(std::shared_ptr(), SyncState::Idle, false, true); DEV_INVARIANT_CHECK; } -void PV60Sync::onPeerAborting(EthereumPeer* _peer) +void PV60Sync::onPeerAborting() { RecursiveGuard l(x_sync); // Can't check invariants here since the peers is already removed from the list and the state is not updated yet. - abortSync(_peer); + if (m_syncer.expired()) + abortSync(); DEV_INVARIANT_CHECK; } bool PV60Sync::invariants() const { - if (m_state == SyncState::Idle && !!m_syncer) + if (m_state == SyncState::Idle && isSyncing()) return false; - if (m_state != SyncState::Idle && !m_syncer) + if (m_state != SyncState::Idle && !isSyncing()) return false; if (m_state == SyncState::Hashes) { bool hashes = false; - host().foreachPeer([&](EthereumPeer* _p) { if (_p->m_asking == Asking::Hashes) hashes = true; return !hashes; }); + host().foreachPeer([&](std::shared_ptr _p) { if (_p->m_asking == Asking::Hashes) hashes = true; return !hashes; }); if (!hashes) return false; if (!m_syncingLatestHash) @@ -781,7 +804,7 @@ bool PV60Sync::invariants() const if (m_state == SyncState::Blocks || m_state == SyncState::NewBlocks) { bool blocks = false; - host().foreachPeer([&](EthereumPeer* _p) { if (_p->m_asking == Asking::Blocks) blocks = true; return !blocks; }); + host().foreachPeer([&](std::shared_ptr _p) { if (_p->m_asking == Asking::Blocks) blocks = true; return !blocks; }); if (!blocks) return false; if (downloadMan().isComplete()) @@ -790,7 +813,7 @@ bool PV60Sync::invariants() const if (m_state == SyncState::Idle) { bool busy = false; - host().foreachPeer([&](EthereumPeer* _p) { if (_p->m_asking != Asking::Nothing && _p->m_asking != Asking::State) busy = true; return !busy; }); + host().foreachPeer([&](std::shared_ptr _p) { if (_p->m_asking != Asking::Nothing && _p->m_asking != Asking::State) busy = true; return !busy; }); if (busy) return false; } diff --git a/libethereum/BlockChainSync.h b/libethereum/BlockChainSync.h index b946f557e..449dd49d1 100644 --- a/libethereum/BlockChainSync.h +++ b/libethereum/BlockChainSync.h @@ -60,22 +60,22 @@ public: virtual bool isSyncing() const = 0; /// Called by peer to report status - virtual void onPeerStatus(EthereumPeer* _peer); + virtual void onPeerStatus(std::shared_ptr _peer); /// Called by peer once it has new blocks during syn - virtual void onPeerBlocks(EthereumPeer* _peer, RLP const& _r); + virtual void onPeerBlocks(std::shared_ptr _peer, RLP const& _r); /// Called by peer once it has new blocks - virtual void onPeerNewBlock(EthereumPeer* _peer, RLP const& _r); + virtual void onPeerNewBlock(std::shared_ptr _peer, RLP const& _r); /// Called by peer once it has new hashes - virtual void onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) = 0; + virtual void onPeerNewHashes(std::shared_ptr _peer, h256s const& _hashes) = 0; /// Called by peer once it has another sequential block of hashes during sync - virtual void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) = 0; + virtual void onPeerHashes(std::shared_ptr _peer, h256s const& _hashes) = 0; /// Called by peer when it is disconnecting - virtual void onPeerAborting(EthereumPeer* _peer) = 0; + virtual void onPeerAborting() = 0; /// @returns Synchonization status virtual SyncStatus status() const = 0; @@ -85,10 +85,10 @@ public: protected: //To be implemented in derived classes: /// New valid peer appears - virtual void onNewPeer(EthereumPeer* _peer) = 0; + virtual void onNewPeer(std::shared_ptr _peer) = 0; /// Peer done downloading blocks - virtual void peerDoneBlocks(EthereumPeer* _peer) = 0; + virtual void peerDoneBlocks(std::shared_ptr _peer) = 0; /// Resume downloading after witing state virtual void continueSync() = 0; @@ -103,7 +103,7 @@ protected: virtual void pauseSync() = 0; /// Restart sync for given peer - virtual void resetSyncFor(EthereumPeer* _peer, h256 const& _latestHash, u256 const& _td) = 0; + virtual void resetSyncFor(std::shared_ptr _peer, h256 const& _latestHash, u256 const& _td) = 0; EthereumHost& host() { return m_host; } EthereumHost const& host() const { return m_host; } @@ -112,17 +112,20 @@ protected: unsigned estimatedHashes() const; /// Request blocks from peer if needed - void requestBlocks(EthereumPeer* _peer); + void requestBlocks(std::shared_ptr _peer); protected: Handler m_bqRoomAvailable; ///< Triggered once block queue mutable RecursiveMutex x_sync; SyncState m_state = SyncState::Idle; ///< Current sync state unsigned m_estimatedHashes = 0; ///< Number of estimated hashes for the last peer over PV60. Used for status reporting only. + h256Hash m_knownNewHashes; ///< New hashes we know about use for logging only private: static char const* const s_stateNames[static_cast(SyncState::Size)]; bool invariants() const override = 0; + void logNewBlock(h256 const& _h); + EthereumHost& m_host; HashDownloadMan m_hashMan; }; @@ -202,65 +205,65 @@ public: PV60Sync(EthereumHost& _host); /// @returns true is Sync is in progress - bool isSyncing() const override { return !!m_syncer; } + bool isSyncing() const override { return !!m_syncer.lock(); } /// Called by peer once it has new hashes - void onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) override; + void onPeerNewHashes(std::shared_ptr _peer, h256s const& _hashes) override; /// Called by peer once it has another sequential block of hashes during sync - void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) override; + void onPeerHashes(std::shared_ptr _peer, h256s const& _hashes) override; /// Called by peer when it is disconnecting - void onPeerAborting(EthereumPeer* _peer) override; + void onPeerAborting() override; /// @returns Sync status SyncStatus status() const override; protected: - void onNewPeer(EthereumPeer* _peer) override; + void onNewPeer(std::shared_ptr _peer) override; void continueSync() override; - void peerDoneBlocks(EthereumPeer* _peer) override; + void peerDoneBlocks(std::shared_ptr _peer) override; void restartSync() override; void completeSync() override; void pauseSync() override; - void resetSyncFor(EthereumPeer* _peer, h256 const& _latestHash, u256 const& _td) override; + void resetSyncFor(std::shared_ptr _peer, h256 const& _latestHash, u256 const& _td) override; private: /// Transition sync state in a particular direction. @param _peer Peer that is responsible for state tranfer - void transition(EthereumPeer* _peer, SyncState _s, bool _force = false, bool _needHelp = true); + void transition(std::shared_ptr _peer, SyncState _s, bool _force = false, bool _needHelp = true); /// Reset peer syncing requirements state. - void resetNeedsSyncing(EthereumPeer* _peer) { setNeedsSyncing(_peer, h256(), 0); } + void resetNeedsSyncing(std::shared_ptr _peer) { setNeedsSyncing(_peer, h256(), 0); } /// Update peer syncing requirements state. - void setNeedsSyncing(EthereumPeer* _peer, h256 const& _latestHash, u256 const& _td); + void setNeedsSyncing(std::shared_ptr _peer, h256 const& _latestHash, u256 const& _td); /// Do we presently need syncing with this peer? - bool needsSyncing(EthereumPeer* _peer) const; + bool needsSyncing(std::shared_ptr _peer) const; /// Check whether the session should bother grabbing blocks from a peer. - bool shouldGrabBlocks(EthereumPeer* _peer) const; + bool shouldGrabBlocks(std::shared_ptr _peer) const; /// Attempt to begin syncing with the peer; first check the peer has a more difficlult chain to download, then start asking for hashes, then move to blocks - void attemptSync(EthereumPeer* _peer); + void attemptSync(std::shared_ptr _peer); /// Update our syncing state - void setState(EthereumPeer* _peer, SyncState _s, bool _isSyncing = false, bool _needHelp = false); + void setState(std::shared_ptr _peer, SyncState _s, bool _isSyncing = false, bool _needHelp = false); /// Check if peer is main syncer - bool isSyncing(EthereumPeer* _peer) const; + bool isSyncing(std::shared_ptr _peer) const; /// Check if we need (re-)syncing with the peer. - void noteNeedsSyncing(EthereumPeer* _who); + void noteNeedsSyncing(std::shared_ptr _who); /// Set main syncing peer - void changeSyncer(EthereumPeer* _syncer, bool _needHelp); + void changeSyncer(std::shared_ptr _syncer, bool _needHelp); /// Called when peer done downloading blocks - void noteDoneBlocks(EthereumPeer* _who, bool _clemency); + void noteDoneBlocks(std::shared_ptr _who, bool _clemency); - /// Abort syncing for peer - void abortSync(EthereumPeer* _peer); + /// Abort syncing + void abortSync(); /// Reset hash chain syncing void resetSync(); @@ -271,8 +274,7 @@ private: h256 m_syncingLastReceivedHash; ///< Hash most recently received from peer. h256 m_syncingLatestHash; ///< Latest block's hash of the peer we are syncing to, as of the current sync. u256 m_syncingTotalDifficulty; ///< Latest block's total difficulty of the peer we aresyncing to, as of the current sync. - // TODO: switch to weak_ptr - EthereumPeer* m_syncer = nullptr; ///< Peer we are currently syncing with + std::weak_ptr m_syncer; ///< Peer we are currently syncing with }; } } diff --git a/libethereum/BlockDetails.h b/libethereum/BlockDetails.h index 19e2c7c7a..f1526b5fd 100644 --- a/libethereum/BlockDetails.h +++ b/libethereum/BlockDetails.h @@ -22,15 +22,10 @@ #pragma once #include -#pragma warning(push) -#pragma warning(disable: 4100 4267) -#include -#pragma warning(pop) - +#include #include #include #include "TransactionReceipt.h" -namespace ldb = leveldb; namespace dev { diff --git a/libethereum/BlockQueue.cpp b/libethereum/BlockQueue.cpp index 394549076..9e647c9c1 100644 --- a/libethereum/BlockQueue.cpp +++ b/libethereum/BlockQueue.cpp @@ -36,6 +36,7 @@ const char* BlockQueueChannel::name() { return EthOrange "[]>"; } #else const char* BlockQueueChannel::name() { return EthOrange "▣┅▶"; } #endif +const char* BlockQueueTraceChannel::name() { return EthOrange "▣ ▶"; } size_t const c_maxKnownCount = 100000; size_t const c_maxKnownSize = 128 * 1024 * 1024; @@ -183,14 +184,14 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo // Check if we already know this block. h256 h = BlockInfo::headerHash(_block); - cblockq << "Queuing block" << h << "for import..."; + clog(BlockQueueTraceChannel) << "Queuing block" << h << "for import..."; UpgradableGuard l(m_lock); if (m_readySet.count(h) || m_drainingSet.count(h) || m_unknownSet.count(h) || m_knownBad.count(h)) { // Already know about this one. - cblockq << "Already known."; + clog(BlockQueueTraceChannel) << "Already known."; return ImportResult::AlreadyKnown; } @@ -228,7 +229,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo time_t bit = (unsigned)bi.timestamp; 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; + clog(BlockQueueTraceChannel) << "OK - queued for future [" << bi.timestamp << "vs" << time(0) << "] - will wait until" << buf; m_unknownSize += _block.size(); m_unknownCount++; m_difficulty += bi.difficulty; @@ -248,7 +249,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo else if (!m_readySet.count(bi.parentHash) && !m_drainingSet.count(bi.parentHash) && !_bc.isKnown(bi.parentHash)) { // We don't know the parent (yet) - queue it up for later. It'll get resent to us if we find out about its ancestry later on. - cblockq << "OK - queued as unknown parent:" << bi.parentHash; + clog(BlockQueueTraceChannel) << "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(); @@ -260,7 +261,7 @@ ImportResult BlockQueue::import(bytesConstRef _block, BlockChain const& _bc, boo else { // If valid, append to blocks. - cblockq << "OK - ready for chain insertion."; + clog(BlockQueueTraceChannel) << "OK - ready for chain insertion."; DEV_GUARDED(m_verification) m_unverified.push_back(UnverifiedBlock { h, bi.parentHash, _block.toBytes() }); m_moreToVerify.notify_one(); diff --git a/libethereum/BlockQueue.h b/libethereum/BlockQueue.h index 106c08534..137048ec4 100644 --- a/libethereum/BlockQueue.h +++ b/libethereum/BlockQueue.h @@ -42,6 +42,7 @@ namespace eth class BlockChain; struct BlockQueueChannel: public LogChannel { static const char* name(); static const int verbosity = 4; }; +struct BlockQueueTraceChannel: public LogChannel { static const char* name(); static const int verbosity = 7; }; #define cblockq dev::LogOutputStream() struct BlockQueueStatus diff --git a/libethereum/CMakeLists.txt b/libethereum/CMakeLists.txt index 6598e1bd7..e896c712b 100644 --- a/libethereum/CMakeLists.txt +++ b/libethereum/CMakeLists.txt @@ -12,7 +12,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) include_directories(BEFORE ..) -include_directories(${LEVELDB_INCLUDE_DIRS}) +include_directories(${DB_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS}) if (JSONRPC) include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) @@ -31,7 +31,6 @@ target_link_libraries(${EXECUTABLE} whisper) target_link_libraries(${EXECUTABLE} p2p) target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} ethcore) -target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${Boost_REGEX_LIBRARIES}) target_link_libraries(${EXECUTABLE} secp256k1) if (JSONRPC) diff --git a/libethereum/CanonBlockChain.h b/libethereum/CanonBlockChain.h index d4494c957..c16479f0d 100644 --- a/libethereum/CanonBlockChain.h +++ b/libethereum/CanonBlockChain.h @@ -21,11 +21,6 @@ #pragma once -#pragma warning(push) -#pragma warning(disable: 4100 4267) -#include -#pragma warning(pop) - #include #include #include @@ -35,7 +30,6 @@ #include "BlockDetails.h" #include "Account.h" #include "BlockChain.h" -namespace ldb = leveldb; namespace dev { diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 7560f9165..ad551c2ec 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -87,6 +87,18 @@ void VersionChecker::setOk() } } +ImportResult Client::queueBlock(bytes const& _block, bool _isSafe) +{ + if (m_bq.status().verified + m_bq.status().verifying + m_bq.status().unverified > 30000) + this_thread::sleep_for(std::chrono::milliseconds(500)); + return m_bq.import(&_block, bc(), _isSafe); +} + +tuple Client::syncQueue(unsigned _max) +{ + return m_bc.sync(m_bq, m_stateDB, _max); +} + void Client::onBadBlock(Exception& _ex) const { // BAD BLOCK!!! @@ -159,7 +171,9 @@ void Client::onBadBlock(Exception& _ex) const DEV_HINT_ERRINFO(max); DEV_HINT_ERRINFO(name); DEV_HINT_ERRINFO(field); + DEV_HINT_ERRINFO(transaction); DEV_HINT_ERRINFO(data); + DEV_HINT_ERRINFO(phase); DEV_HINT_ERRINFO_HASH(nonce); DEV_HINT_ERRINFO(difficulty); DEV_HINT_ERRINFO(target); @@ -355,11 +369,19 @@ bool Client::isSyncing() const return false; } +bool Client::isMajorSyncing() const +{ + // TODO: only return true if it is actually doing a proper chain sync. + if (auto h = m_host.lock()) + return h->isSyncing(); + return false; +} + void Client::startedWorking() { // Synchronise the state according to the head of the block chain. // TODO: currently it contains keys for *all* blocks. Make it remove old ones. - cdebug << "startedWorking()"; + clog(ClientTrace) << "startedWorking()"; DEV_WRITE_GUARDED(x_preMine) m_preMine.sync(m_bc); @@ -555,7 +577,7 @@ ExecutionResult Client::call(Address _dest, bytes const& _data, u256 _gas, u256 try { State temp; -// cdebug << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); +// clog(ClientTrace) << "Nonce at " << toAddress(_secret) << " pre:" << m_preMine.transactionsFrom(toAddress(_secret)) << " post:" << m_postMine.transactionsFrom(toAddress(_secret)); DEV_READ_GUARDED(x_postMine) temp = m_postMine; temp.addBalance(_from, _value + _gasPrice * _gas); @@ -612,22 +634,24 @@ bool Client::submitWork(ProofOfWork::Solution const& _solution) } unsigned static const c_syncMin = 1; -unsigned static const c_syncMax = 100; +unsigned static const c_syncMax = 1000; double static const c_targetDuration = 1; void Client::syncBlockQueue() { - ImportRoute ir; cwork << "BQ ==> CHAIN ==> STATE"; - boost::timer t; - tie(ir, m_syncBlockQueue) = m_bc.sync(m_bq, m_stateDB, m_syncAmount); + ImportRoute ir; + unsigned count; + Timer t; + tie(ir, m_syncBlockQueue, count) = 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 (count) + clog(ClientNote) << count << "blocks imported in" << unsigned(elapsed * 1000) << "ms (" << (count / 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) + if (elapsed > c_targetDuration * 1.1 && count > c_syncMin) + m_syncAmount = max(c_syncMin, count * 9 / 10); + else if (count == m_syncAmount && elapsed < c_targetDuration * 0.9 && m_syncAmount < c_syncMax) m_syncAmount = min(c_syncMax, m_syncAmount * 11 / 10 + 1); if (ir.liveBlocks.empty()) return; @@ -656,7 +680,6 @@ void Client::syncTransactionQueue() for (size_t i = 0; i < newPendingReceipts.size(); i++) appendFromNewPending(newPendingReceipts[i], changeds, m_postMine.pending()[i].sha3()); - // Tell farm about new transaction (i.e. restartProofOfWork mining). onPostStateChanged(); @@ -701,7 +724,7 @@ void Client::onChainChanged(ImportRoute const& _ir) // RESTART MINING - if (!m_bq.items().first) + if (!isMajorSyncing()) { bool preChanged = false; State newPreMine; @@ -714,7 +737,7 @@ void Client::onChainChanged(ImportRoute const& _ir) if (preChanged || m_postMine.address() != m_preMine.address()) { if (isMining()) - cnote << "New block on chain."; + clog(ClientTrace) << "New block on chain."; DEV_WRITE_GUARDED(x_preMine) m_preMine = newPreMine; @@ -751,7 +774,7 @@ bool Client::remoteActive() const void Client::onPostStateChanged() { - cnote << "Post state changed."; + clog(ClientTrace) << "Post state changed."; rejigMining(); m_remoteWorking = false; } @@ -764,9 +787,9 @@ void Client::startMining() void Client::rejigMining() { - if ((wouldMine() || remoteActive()) && !m_bq.items().first && (!isChainBad() || mineOnBadChain()) /*&& (forceMining() || transactionsWaiting())*/) + if ((wouldMine() || remoteActive()) && !isMajorSyncing() && (!isChainBad() || mineOnBadChain()) /*&& (forceMining() || transactionsWaiting())*/) { - cnote << "Rejigging mining..."; + clog(ClientTrace) << "Rejigging mining..."; DEV_WRITE_GUARDED(x_working) m_working.commitToMine(m_bc); DEV_READ_GUARDED(x_working) @@ -863,7 +886,7 @@ void Client::checkWatchGarbage() if (m_watches[key].lastPoll != chrono::system_clock::time_point::max() && chrono::system_clock::now() - m_watches[key].lastPoll > chrono::seconds(20)) { toUninstall.push_back(key); - cnote << "GC: Uninstall" << key << "(" << chrono::duration_cast(chrono::system_clock::now() - m_watches[key].lastPoll).count() << "s old)"; + clog(ClientTrace) << "GC: Uninstall" << key << "(" << chrono::duration_cast(chrono::system_clock::now() - m_watches[key].lastPoll).count() << "s old)"; } for (auto i: toUninstall) uninstallWatch(i); diff --git a/libethereum/Client.h b/libethereum/Client.h index c8aad1670..f38c7c099 100644 --- a/libethereum/Client.h +++ b/libethereum/Client.h @@ -138,6 +138,9 @@ public: /// Blocks until all pending transactions have been processed. virtual void flushTransactions() override; + /// Queues a block for import. + ImportResult queueBlock(bytes const& _block, bool _isSafe = false); + using Interface::call; // to remove warning about hiding virtual function /// Makes the given call. Nothing is recorded into the state. This cheats by creating a null address and endowing it with a lot of ETH. ExecutionResult call(Address _dest, bytes const& _data = bytes(), u256 _gas = 125000, u256 _value = 0, u256 _gasPrice = 1 * ether, Address const& _from = Address()); @@ -160,6 +163,11 @@ public: SyncStatus syncStatus() const; /// Get the block queue. BlockQueue const& blockQueue() const { return m_bq; } + /// Get the block queue. + OverlayDB const& stateDB() const { return m_stateDB; } + + /// Freeze worker thread and sync some of the block queue. + std::tuple syncQueue(unsigned _max = 1); // Mining stuff: @@ -219,6 +227,7 @@ public: DownloadMan const* downloadMan() const; bool isSyncing() const; + bool isMajorSyncing() const; /// Sets the network id. void setNetworkId(u256 _n); /// Clears pending transactions. Just for debug use. diff --git a/libethereum/ClientBase.cpp b/libethereum/ClientBase.cpp index d5bc0dbb9..2ac413a6a 100644 --- a/libethereum/ClientBase.cpp +++ b/libethereum/ClientBase.cpp @@ -56,6 +56,19 @@ void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, b cnote << "New transaction " << t; } +Address ClientBase::submitTransaction(Secret _secret, u256 _value, bytes const& _data, u256 _gas, u256 _gasPrice, u256 _nonce) +{ + prepareForTransaction(); + + Transaction t(_value, _gasPrice, _gas, _data, _nonce, _secret); + m_tq.import(t.rlp()); + + StructuredLogger::transactionReceived(t.sha3().abridged(), t.sender().abridged()); + cnote << "New transaction " << t; + + return right160(sha3(rlpList(t.sender(), t.nonce()))); +} + void ClientBase::submitTransaction(Secret _secret, u256 _value, Address _dest, bytes const& _data, u256 _gas, u256 _gasPrice) { auto a = toAddress(_secret); diff --git a/libethereum/ClientBase.h b/libethereum/ClientBase.h index 8aa84101c..ebcc48c18 100644 --- a/libethereum/ClientBase.h +++ b/libethereum/ClientBase.h @@ -81,6 +81,7 @@ public: /// Submits a new contract-creation transaction. /// @returns the new contract's address (assuming it all goes through). + virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas, u256 _gasPrice, u256 _nonce); virtual Address submitTransaction(Secret _secret, u256 _endowment, bytes const& _init, u256 _gas = 10000, u256 _gasPrice = 10 * szabo) override; using Interface::submitTransaction; diff --git a/libethereum/EthereumHost.cpp b/libethereum/EthereumHost.cpp index f693ff768..9980f4339 100644 --- a/libethereum/EthereumHost.cpp +++ b/libethereum/EthereumHost.cpp @@ -41,7 +41,6 @@ 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", "Waiting", "Hashes", "Blocks", "NewBlocks" }; @@ -105,7 +104,7 @@ void EthereumHost::doWork() } } - foreachPeer([](EthereumPeer* _p) { _p->tick(); return true; }); + foreachPeer([](std::shared_ptr _p) { _p->tick(); return true; }); // return netChange; // TODO: Figure out what to do with netChange. @@ -126,7 +125,7 @@ void EthereumHost::maintainTransactions() } for (auto const& t: ts) m_transactionsSent.insert(t.first); - foreachPeerPtr([&](shared_ptr _p) + foreachPeer([&](shared_ptr _p) { bytes b; unsigned n = 0; @@ -151,17 +150,7 @@ void EthereumHost::maintainTransactions() }); } -void EthereumHost::foreachPeer(std::function const& _f) const -{ - foreachPeerPtr([&](std::shared_ptr _p) - { - if (_p) - return _f(_p.get()); - return true; - }); -} - -void EthereumHost::foreachPeerPtr(std::function)> const& _f) const +void EthereumHost::foreachPeer(std::function)> const& _f) const { for (auto s: peerSessions()) if (!_f(s.first->cap())) @@ -177,20 +166,21 @@ tuple>, vector>, vector vector> allowed; vector> sessions; - auto const& ps = peerSessions(); - allowed.reserve(ps.size()); - for (auto const& j: ps) + size_t peerCount = 0; + foreachPeer([&](std::shared_ptr _p) { - auto pp = j.first->cap(); - if (_allow(pp.get())) + if (_allow(_p.get())) { - allowed.push_back(move(pp)); - sessions.push_back(move(j.first)); + allowed.push_back(_p); + sessions.push_back(_p->session()); } - } + ++peerCount; + return true; + }); - chosen.reserve((ps.size() * _percent + 99) / 100); - for (unsigned i = (ps.size() * _percent + 99) / 100; i-- && allowed.size();) + size_t chosenSize = (peerCount * _percent + 99) / 100; + chosen.reserve(chosenSize); + for (unsigned i = chosenSize; i && allowed.size(); i--) { unsigned n = rand() % allowed.size(); chosen.push_back(std::move(allowed[n])); @@ -246,7 +236,7 @@ BlockChainSync& EthereumHost::sync() return *m_sync; // We only chose sync strategy once bool pv61 = false; - foreachPeer([&](EthereumPeer* _p) + foreachPeer([&](std::shared_ptr _p) { if (_p->m_protocolVersion == protocolVersion()) pv61 = true; @@ -256,37 +246,37 @@ BlockChainSync& EthereumHost::sync() return *m_sync; } -void EthereumHost::onPeerStatus(EthereumPeer* _peer) +void EthereumHost::onPeerStatus(std::shared_ptr _peer) { Guard l(x_sync); sync().onPeerStatus(_peer); } -void EthereumHost::onPeerHashes(EthereumPeer* _peer, h256s const& _hashes) +void EthereumHost::onPeerHashes(std::shared_ptr _peer, h256s const& _hashes) { Guard l(x_sync); sync().onPeerHashes(_peer, _hashes); } -void EthereumHost::onPeerBlocks(EthereumPeer* _peer, RLP const& _r) +void EthereumHost::onPeerBlocks(std::shared_ptr _peer, RLP const& _r) { Guard l(x_sync); sync().onPeerBlocks(_peer, _r); } -void EthereumHost::onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes) +void EthereumHost::onPeerNewHashes(std::shared_ptr _peer, h256s const& _hashes) { Guard l(x_sync); sync().onPeerNewHashes(_peer, _hashes); } -void EthereumHost::onPeerNewBlock(EthereumPeer* _peer, RLP const& _r) +void EthereumHost::onPeerNewBlock(std::shared_ptr _peer, RLP const& _r) { Guard l(x_sync); sync().onPeerNewBlock(_peer, _r); } -void EthereumHost::onPeerTransactions(EthereumPeer* _peer, RLP const& _r) +void EthereumHost::onPeerTransactions(std::shared_ptr _peer, RLP const& _r) { if (_peer->isCriticalSyncing()) { @@ -319,11 +309,11 @@ void EthereumHost::onPeerTransactions(EthereumPeer* _peer, RLP const& _r) } } -void EthereumHost::onPeerAborting(EthereumPeer* _peer) +void EthereumHost::onPeerAborting() { Guard l(x_sync); if (m_sync) - m_sync->onPeerAborting(_peer); + m_sync->onPeerAborting(); } bool EthereumHost::isSyncing() const diff --git a/libethereum/EthereumHost.h b/libethereum/EthereumHost.h index 8e79d1cf8..182c3d4cd 100644 --- a/libethereum/EthereumHost.h +++ b/libethereum/EthereumHost.h @@ -86,16 +86,15 @@ public: static char const* stateName(SyncState _s) { return s_stateNames[static_cast(_s)]; } static unsigned const c_oldProtocolVersion; - void foreachPeerPtr(std::function)> const& _f) const; - void foreachPeer(std::function const& _f) const; - - void onPeerStatus(EthereumPeer* _peer); - void onPeerHashes(EthereumPeer* _peer, h256s const& _hashes); - void onPeerBlocks(EthereumPeer* _peer, RLP const& _r); - void onPeerNewHashes(EthereumPeer* _peer, h256s const& _hashes); - void onPeerNewBlock(EthereumPeer* _peer, RLP const& _r); - void onPeerTransactions(EthereumPeer* _peer, RLP const& _r); - void onPeerAborting(EthereumPeer* _peer); + void foreachPeer(std::function)> const& _f) const; + + void onPeerStatus(std::shared_ptr _peer); + void onPeerHashes(std::shared_ptr _peer, h256s const& _hashes); + void onPeerBlocks(std::shared_ptr _peer, RLP const& _r); + void onPeerNewHashes(std::shared_ptr _peer, h256s const& _hashes); + void onPeerNewBlock(std::shared_ptr _peer, RLP const& _r); + void onPeerTransactions(std::shared_ptr _peer, RLP const& _r); + void onPeerAborting(); private: static char const* const s_stateNames[static_cast(SyncState::Size)]; diff --git a/libethereum/EthereumPeer.cpp b/libethereum/EthereumPeer.cpp index 87d51969a..30c2bfc9a 100644 --- a/libethereum/EthereumPeer.cpp +++ b/libethereum/EthereumPeer.cpp @@ -49,7 +49,7 @@ string toString(Asking _a) return "?"; } -EthereumPeer::EthereumPeer(Session* _s, HostCapabilityFace* _h, unsigned _i, CapDesc const& _cap): +EthereumPeer::EthereumPeer(std::shared_ptr _s, HostCapabilityFace* _h, unsigned _i, CapDesc const& _cap): Capability(_s, _h, _i), m_sub(host()->downloadMan()), m_peerCapabilityVersion(_cap.second) @@ -71,27 +71,39 @@ EthereumPeer::~EthereumPeer() bool EthereumPeer::isRude() const { - return repMan().isRude(*session(), name()); + auto s = session(); + if (s) + return repMan().isRude(*s, name()); + return false; } unsigned EthereumPeer::askOverride() const { - bytes const& d = repMan().data(*session(), name()); + std::string static const badGeth = "Geth/v0.9.27"; + auto s = session(); + if (!s) + return c_maxBlocksAsk; + if (s->info().clientVersion.substr(0, badGeth.size()) == badGeth) + return 1; + bytes const& d = repMan().data(*s, name()); return d.empty() ? c_maxBlocksAsk : RLP(d).toInt(RLP::LaisezFaire); } void EthereumPeer::setRude() { + auto s = session(); + if (!s) + return; auto old = askOverride(); - repMan().setData(*session(), name(), rlp(askOverride() / 2 + 1)); + repMan().setData(*s, name(), rlp(askOverride() / 2 + 1)); cnote << "Rude behaviour; askOverride now" << askOverride() << ", was" << old; - repMan().noteRude(*session(), name()); + repMan().noteRude(*s, name()); session()->addNote("manners", "RUDE"); } void EthereumPeer::abortSync() { - host()->onPeerAborting(this); + host()->onPeerAborting(); } EthereumHost* EthereumPeer::host() const @@ -150,6 +162,21 @@ void EthereumPeer::requestHashes(h256 const& _lastHash) sealAndSend(s); } +void EthereumPeer::requestBlocks(h256s const& _blocks) +{ + setAsking(Asking::Blocks); + if (_blocks.size()) + { + RLPStream s; + prep(s, GetBlocksPacket, _blocks.size()); + for (auto const& i: _blocks) + s << i; + sealAndSend(s); + } + else + setIdle(); +} + void EthereumPeer::requestBlocks() { setAsking(Asking::Blocks); @@ -164,7 +191,6 @@ void EthereumPeer::requestBlocks() } else setIdle(); - return; } void EthereumPeer::setAsking(Asking _a) @@ -172,15 +198,20 @@ void EthereumPeer::setAsking(Asking _a) m_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(isCriticalSyncing() ? "ONGOING" : "holding") + (needsSyncing() ? " & needed" : "")); + auto s = session(); + if (s) + { + s->addNote("ask", _a == Asking::Nothing ? "nothing" : _a == Asking::State ? "state" : _a == Asking::Hashes ? "hashes" : _a == Asking::Blocks ? "blocks" : "?"); + s->addNote("sync", string(isCriticalSyncing() ? "ONGOING" : "holding") + (needsSyncing() ? " & needed" : "")); + } } void EthereumPeer::tick() { - if (chrono::system_clock::now() - m_lastAsk > chrono::seconds(10) && m_asking != Asking::Nothing) + auto s = session(); + if (s && (chrono::system_clock::now() - m_lastAsk > chrono::seconds(10) && m_asking != Asking::Nothing)) // timeout - session()->disconnect(PingTimeout); + s->disconnect(PingTimeout); } bool EthereumPeer::isConversing() const @@ -222,12 +253,12 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) clog(NetMessageSummary) << "Status:" << m_protocolVersion << "/" << m_networkId << "/" << m_genesisHash << "/" << m_latestBlockNumber << ", TD:" << m_totalDifficulty << "=" << m_latestHash; setAsking(Asking::Nothing); - host()->onPeerStatus(this); + host()->onPeerStatus(dynamic_pointer_cast(dynamic_pointer_cast(shared_from_this()))); break; } case TransactionsPacket: { - host()->onPeerTransactions(this, _r); + host()->onPeerTransactions(dynamic_pointer_cast(dynamic_pointer_cast(shared_from_this())), _r); break; } case GetBlockHashesPacket: @@ -282,7 +313,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) for (unsigned i = 0; i < itemCount; ++i) hashes[i] = _r[i].toHash(); - host()->onPeerHashes(this, hashes); + host()->onPeerHashes(dynamic_pointer_cast(shared_from_this()), hashes); break; } case GetBlocksPacket: @@ -324,12 +355,12 @@ 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 - host()->onPeerBlocks(this, _r); + host()->onPeerBlocks(dynamic_pointer_cast(shared_from_this()), _r); break; } case NewBlockPacket: { - host()->onPeerNewBlock(this, _r); + host()->onPeerNewBlock(dynamic_pointer_cast(shared_from_this()), _r); break; } case NewBlockHashesPacket: @@ -341,7 +372,7 @@ bool EthereumPeer::interpret(unsigned _id, RLP const& _r) for (unsigned i = 0; i < itemCount; ++i) hashes[i] = _r[i].toHash(); - host()->onPeerNewHashes(this, hashes); + host()->onPeerNewHashes(dynamic_pointer_cast(shared_from_this()), hashes); break; } default: diff --git a/libethereum/EthereumPeer.h b/libethereum/EthereumPeer.h index 9d5b91b47..d506ffb3f 100644 --- a/libethereum/EthereumPeer.h +++ b/libethereum/EthereumPeer.h @@ -56,7 +56,7 @@ class EthereumPeer: public p2p::Capability public: /// Basic constructor. - EthereumPeer(p2p::Session* _s, p2p::HostCapabilityFace* _h, unsigned _i, p2p::CapDesc const& _cap); + EthereumPeer(std::shared_ptr _s, p2p::HostCapabilityFace* _h, unsigned _i, p2p::CapDesc const& _cap); /// Basic destructor. virtual ~EthereumPeer(); @@ -85,6 +85,9 @@ public: /// Request blocks. Uses block download manager. void requestBlocks(); + /// Request specified blocks from peer. + void requestBlocks(h256s const& _blocks); + /// Check if this node is rude. bool isRude() const; diff --git a/libethereum/Executive.cpp b/libethereum/Executive.cpp index 9bf0cc74f..02e263ab1 100644 --- a/libethereum/Executive.cpp +++ b/libethereum/Executive.cpp @@ -316,7 +316,7 @@ bool Executive::go(OnOpFunc const& _onOp) if (m_ext) { #if ETH_TIMED_EXECUTIONS - boost::timer t; + Timer t; #endif try { diff --git a/libethereum/State.cpp b/libethereum/State.cpp index f56c12c91..ead72f496 100644 --- a/libethereum/State.cpp +++ b/libethereum/State.cpp @@ -139,7 +139,7 @@ PopulationStatistics State::populateFromChain(BlockChain const& _bc, h256 const& // 2. Enact the block's transactions onto this state. m_ourAddress = bi.coinbaseAddress; - boost::timer t; + Timer t; auto vb = BlockChain::verifyBlock(b); ret.verify = t.elapsed(); t.restart(); @@ -401,7 +401,7 @@ bool State::sync(BlockChain const& _bc, h256 _block, BlockInfo const& _bi, Impor u256 State::enactOn(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportRequirements::value _ir) { #if ETH_TIMED_ENACTMENTS - boost::timer t; + Timer t; double populateVerify; double populateGrand; double syncReset; @@ -456,7 +456,7 @@ unordered_map State::addresses() const ret[i.first] = RLP(i.second)[1].toInt(); return ret; #else - throw InterfaceNotSupported("State::addresses()"); + BOOST_THROW_EXCEPTION(InterfaceNotSupported("State::addresses()")); #endif } @@ -507,7 +507,7 @@ pair State::sync(BlockChain const& _bc, TransactionQu { if (i.second.gasPrice() >= _gp.ask(*this)) { - // boost::timer t; + // Timer t; if (lh.empty()) lh = _bc.lastHashes(); execute(lh, i.second); @@ -531,8 +531,20 @@ pair State::sync(BlockChain const& _bc, TransactionQu if (req > got) { // too old - cnote << i.first << "Dropping old transaction (nonce too low)"; - _tq.drop(i.first); + for (Transaction const& t: m_transactions) + if (t.from() == i.second.from()) + { + if (t.nonce() < i.second.nonce()) + { + cnote << i.first << "Dropping old transaction (nonce too low)"; + _tq.drop(i.first); + } + else if (t.nonce() == i.second.nonce() && t.gasPrice() <= i.second.gasPrice()) + { + cnote << i.first << "Dropping old transaction (gas price lower)"; + _tq.drop(i.first); + } + } } else if (got > req + _tq.waiting(i.second.sender())) { @@ -634,7 +646,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR // cnote << m_state; LastHashes lh; - DEV_TIMED_ABOVE(lastHashes, 500) + DEV_TIMED_ABOVE("lastHashes", 500) lh = _bc.lastHashes((unsigned)m_previousBlock.number); RLP rlp(_block.block); @@ -643,7 +655,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR // All ok with the block generally. Play back the transactions now... unsigned i = 0; - DEV_TIMED_ABOVE(txEcec, 500) + DEV_TIMED_ABOVE("txExec", 500) for (auto const& tr: _block.transactions) { try @@ -664,7 +676,7 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR } h256 receiptsRoot; - DEV_TIMED_ABOVE(receiptsRoot, 500) + DEV_TIMED_ABOVE("receiptsRoot", 500) receiptsRoot = orderedTrieRoot(receipts); if (receiptsRoot != m_currentBlock.receiptsRoot) @@ -698,12 +710,12 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR vector rewarded; h256Hash excluded; - DEV_TIMED_ABOVE(allKin, 500) + DEV_TIMED_ABOVE("allKin", 500) excluded = _bc.allKinFrom(m_currentBlock.parentHash, 6); excluded.insert(m_currentBlock.hash()); unsigned ii = 0; - DEV_TIMED_ABOVE(uncleCheck, 500) + DEV_TIMED_ABOVE("uncleCheck", 500) for (auto const& i: rlp[2]) { try @@ -752,11 +764,11 @@ u256 State::enact(VerifiedBlockRef const& _block, BlockChain const& _bc, ImportR } } - DEV_TIMED_ABOVE(applyRewards, 500) + DEV_TIMED_ABOVE("applyRewards", 500) applyRewards(rewarded); // Commit all cached state changes to the state trie. - DEV_TIMED_ABOVE(commit, 500) + DEV_TIMED_ABOVE("commit", 500) commit(); // Hash the state trie and check against the state_root hash in m_currentBlock. diff --git a/libethereum/State.h b/libethereum/State.h index 3eac63d04..6ad8fed09 100644 --- a/libethereum/State.h +++ b/libethereum/State.h @@ -58,6 +58,8 @@ using errinfo_transactionIndex = boost::error_info; using errinfo_receipts = boost::error_info>; +using errinfo_transaction = boost::error_info; +using errinfo_phase = boost::error_info; using errinfo_required_LogBloom = boost::error_info; using errinfo_got_LogBloom = boost::error_info; using LogBloomRequirementError = boost::tuple; @@ -206,6 +208,8 @@ public: return false; PoW::assignResult(_result, m_currentBlock); + if (!PoW::verify(m_currentBlock)) + return false; cnote << "Completed" << m_currentBlock.headerHash(WithoutNonce) << m_currentBlock.nonce << m_currentBlock.difficulty << PoW::verify(m_currentBlock); diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 58ecc44fa..40a7914d3 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -77,6 +77,7 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, TransactionException cons { case TransactionException::None: _out << "None"; break; case TransactionException::BadRLP: _out << "BadRLP"; break; + case TransactionException::InvalidFormat: _out << "InvalidFormat"; break; case TransactionException::OutOfGasIntrinsic: _out << "OutOfGasIntrinsic"; break; case TransactionException::InvalidSignature: _out << "InvalidSignature"; break; case TransactionException::InvalidNonce: _out << "InvalidNonce"; break; @@ -100,7 +101,7 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckTransaction _checkSig) try { if (!rlp.isList()) - BOOST_THROW_EXCEPTION(BadRLP() << errinfo_comment("transaction RLP must be a list")); + BOOST_THROW_EXCEPTION(InvalidTransactionFormat() << errinfo_comment("transaction RLP must be a list")); m_nonce = rlp[field = 0].toInt(); m_gasPrice = rlp[field = 1].toInt(); @@ -110,7 +111,7 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckTransaction _checkSig) m_value = rlp[field = 4].toInt(); if (!rlp[field = 5].isData()) - BOOST_THROW_EXCEPTION(BadRLP() << errinfo_comment("transaction data RLP must be an array")); + BOOST_THROW_EXCEPTION(InvalidTransactionFormat() << errinfo_comment("transaction data RLP must be an array")); m_data = rlp[field = 5].toBytes(); byte v = rlp[field = 6].toInt() - 27; @@ -118,7 +119,7 @@ Transaction::Transaction(bytesConstRef _rlpData, CheckTransaction _checkSig) h256 s = rlp[field = 8].toInt(); if (rlp.itemCount() > 9) - BOOST_THROW_EXCEPTION(BadRLP() << errinfo_comment("to many fields in the transaction RLP")); + BOOST_THROW_EXCEPTION(InvalidTransactionFormat() << errinfo_comment("to many fields in the transaction RLP")); m_vrs = SignatureStruct{ r, s, v }; if (_checkSig >= CheckTransaction::Cheap && !m_vrs.isValid()) diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index e9b1cbf80..4de9d7e92 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -50,6 +50,7 @@ enum class TransactionException None = 0, Unknown, BadRLP, + InvalidFormat, OutOfGasIntrinsic, ///< Too little gas to pay for the base transaction cost. InvalidSignature, InvalidNonce, diff --git a/libethereum/TransactionQueue.cpp b/libethereum/TransactionQueue.cpp index e488805d9..a86f6abf3 100644 --- a/libethereum/TransactionQueue.cpp +++ b/libethereum/TransactionQueue.cpp @@ -29,6 +29,7 @@ using namespace dev; using namespace dev::eth; const char* TransactionQueueChannel::name() { return EthCyan "┉┅▶"; } +const char* TransactionQueueTraceChannel::name() { return EthCyan " ┅▶"; } ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallback const& _cb, IfDropped _ik) { @@ -38,20 +39,22 @@ ImportResult TransactionQueue::import(bytesConstRef _transactionRLP, ImportCallb Transaction t; ImportResult ir; { - UpgradableGuard l(m_lock); + UpgradableGuard l(m_lock); - ir = check_WITH_LOCK(h, _ik); - if (ir != ImportResult::Success) - return ir; + ir = check_WITH_LOCK(h, _ik); + if (ir != ImportResult::Success) + return ir; - try { - t = Transaction(_transactionRLP, CheckTransaction::Everything); - UpgradeGuard ul(l); - ir = manageImport_WITH_LOCK(h, t, _cb); - } - catch (...) { - return ImportResult::Malformed; - } + try + { + t = Transaction(_transactionRLP, CheckTransaction::Everything); + UpgradeGuard ul(l); + ir = manageImport_WITH_LOCK(h, t, _cb); + } + catch (...) + { + return ImportResult::Malformed; + } } // cdebug << "import-END: Nonce of" << t.sender() << "now" << maxNonce(t.sender()); return ir; @@ -115,7 +118,7 @@ ImportResult TransactionQueue::manageImport_WITH_LOCK(h256 const& _h, Transactio m_known.insert(_h); if (_cb) m_callbacks[_h] = _cb; - ctxq << "Queued vaguely legit-looking transaction" << _h; + clog(TransactionQueueTraceChannel) << "Queued vaguely legit-looking transaction" << _h; m_onReady(); } catch (Exception const& _e) diff --git a/libethereum/TransactionQueue.h b/libethereum/TransactionQueue.h index a07efb848..d9bfef847 100644 --- a/libethereum/TransactionQueue.h +++ b/libethereum/TransactionQueue.h @@ -36,7 +36,8 @@ namespace eth class BlockChain; struct TransactionQueueChannel: public LogChannel { static const char* name(); static const int verbosity = 4; }; -#define ctxq dev::LogOutputStream() +struct TransactionQueueTraceChannel: public LogChannel { static const char* name(); static const int verbosity = 7; }; +#define ctxq dev::LogOutputStream() enum class IfDropped { Ignore, Retry }; diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 34ee05966..c96b6f40d 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -41,7 +41,7 @@ void Assembly::append(Assembly const& _a) if (i.type() == Tag || i.type() == PushTag) i.setData(i.data() + m_usedTags); else if (i.type() == PushSub || i.type() == PushSubSize) - i.setData(i.data() + m_usedTags); + i.setData(i.data() + m_subs.size()); append(i); } m_deposit = newDeposit; @@ -136,10 +136,10 @@ ostream& Assembly::streamAsm(ostream& _out, string const& _prefix, StringMap con _out << " PUSH [tag" << dec << i.data() << "]"; break; case PushSub: - _out << " PUSH [$" << h256(i.data()).abridged() << "]"; + _out << " PUSH [$" << h256(i.data()).abridgedMiddle() << "]"; break; case PushSubSize: - _out << " PUSH #[$" << h256(i.data()).abridged() << "]"; + _out << " PUSH #[$" << h256(i.data()).abridgedMiddle() << "]"; break; case PushProgramSize: _out << " PUSHSIZE"; diff --git a/libevmasm/AssemblyItem.cpp b/libevmasm/AssemblyItem.cpp index a0c5e19a6..e005ece18 100644 --- a/libevmasm/AssemblyItem.cpp +++ b/libevmasm/AssemblyItem.cpp @@ -110,10 +110,10 @@ ostream& dev::eth::operator<<(ostream& _out, AssemblyItem const& _item) _out << " PushData " << hex << (unsigned)_item.data(); break; case PushSub: - _out << " PushSub " << hex << h256(_item.data()).abridged(); + _out << " PushSub " << hex << h256(_item.data()).abridgedMiddle(); break; case PushSubSize: - _out << " PushSubSize " << hex << h256(_item.data()).abridged(); + _out << " PushSubSize " << hex << h256(_item.data()).abridgedMiddle(); break; case PushProgramSize: _out << " PushProgramSize"; diff --git a/libjsconsole/CMakeLists.txt b/libjsconsole/CMakeLists.txt index e8f98de88..761435fe1 100644 --- a/libjsconsole/CMakeLists.txt +++ b/libjsconsole/CMakeLists.txt @@ -14,6 +14,7 @@ include_directories(BEFORE ${V8_INCLUDE_DIRS}) include_directories(BEFORE ..) include_directories(${READLINE_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) +include_directories(${CURL_INCLUDE_DIRS}) set(EXECUTABLE jsconsole) @@ -24,7 +25,12 @@ add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) target_link_libraries(${EXECUTABLE} jsengine) target_link_libraries(${EXECUTABLE} devcore) target_link_libraries(${EXECUTABLE} ${READLINE_LIBRARIES}) -target_link_libraries(${EXECUTABLE} web3jsonrpc) +target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_SERVER_LIBRARIES}) + +target_link_libraries(${EXECUTABLE} ${CURL_LIBRARIES}) +if (DEFINED WIN32 AND NOT DEFINED CMAKE_COMPILER_IS_MINGW) + eth_copy_dlls(${EXECUTABLE} CURL_DLLS) +endif() install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib LIBRARY DESTINATION lib ) install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) diff --git a/libjsconsole/CURLRequest.cpp b/libjsconsole/CURLRequest.cpp new file mode 100644 index 000000000..c07059372 --- /dev/null +++ b/libjsconsole/CURLRequest.cpp @@ -0,0 +1,66 @@ +/* + 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 CURLRequest.cpp + * @author Marek Kotewicz + * @date 2015 + * Ethereum client. + */ + +#include "CURLRequest.h" + +using namespace std; + +static size_t write_data(void *buffer, size_t elementSize, size_t numberOfElements, void *userp) +{ + static_cast(userp)->write((const char *)buffer, elementSize * numberOfElements); + return elementSize * numberOfElements; +} + +void CURLRequest::commonCURLPreparation() +{ + m_resultBuffer.str(""); + curl_easy_setopt(m_curl, CURLOPT_URL, (m_url + "?").c_str()); + curl_easy_setopt(m_curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, write_data); + curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &m_resultBuffer); +} + +std::tuple CURLRequest::commonCURLPerform() +{ + CURLcode res = curl_easy_perform(m_curl); + if (res != CURLE_OK) { + throw runtime_error(curl_easy_strerror(res)); + } + long httpCode = 0; + curl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, &httpCode); + return make_tuple(httpCode, m_resultBuffer.str()); +} + +std::tuple CURLRequest::post() +{ + commonCURLPreparation(); + curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, m_body.c_str()); + + struct curl_slist *headerList = NULL; + headerList = curl_slist_append(headerList, "Content-Type: application/json"); + curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, headerList); + + auto result = commonCURLPerform(); + + curl_slist_free_all(headerList); + return result; +} diff --git a/libjsconsole/CURLRequest.h b/libjsconsole/CURLRequest.h new file mode 100644 index 000000000..e025d1eb9 --- /dev/null +++ b/libjsconsole/CURLRequest.h @@ -0,0 +1,58 @@ +/* + 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 CURLRequest.h + * @author Marek Kotewicz + * @date 2015 + * Ethereum client. + */ + +// based on http://stackoverflow.com/questions/1011339/how-do-you-make-a-http-request-with-c/27026683#27026683 + +#pragma once + +#include +#include +#include +#include + +class CURLRequest +{ +public: + CURLRequest(): m_curl(curl_easy_init()) {} + ~CURLRequest() + { + if (m_curl) + curl_easy_cleanup(m_curl); + } + + void setUrl(std::string _url) { m_url = _url; } + void setBody(std::string _body) { m_body = _body; } + + std::tuple post(); + +private: + std::string m_url; + std::string m_body; + + CURL* m_curl; + std::stringstream m_resultBuffer; + + void commonCURLPreparation(); + std::tuple commonCURLPerform(); +}; + + diff --git a/libjsconsole/JSConsole.cpp b/libjsconsole/JSConsole.cpp index 29d547242..61376de79 100644 --- a/libjsconsole/JSConsole.cpp +++ b/libjsconsole/JSConsole.cpp @@ -20,65 +20,5 @@ * Ethereum client. */ -#include -#include -#include -#include "JSConsole.h" -#include "JSV8Connector.h" - -// TODO! make readline optional! -#include -#include - -using namespace std; -using namespace dev; -using namespace dev::eth; - -JSConsole::JSConsole(WebThreeDirect& _web3, shared_ptr const& _accounts): - m_engine(), - m_printer(m_engine) -{ - m_jsonrpcConnector.reset(new JSV8Connector(m_engine)); - (void)_web3; (void)_accounts; -// m_jsonrpcServer.reset(new WebThreeStubServer(*m_jsonrpcConnector.get(), _web3, _accounts, vector())); -} - -void JSConsole::readExpression() const -{ - string cmd = ""; - g_logPost = [](std::string const& a, char const*) { cout << "\r \r" << a << endl << flush; rl_forced_update_display(); }; - bool isEmpty = true; - int openBrackets = 0; - do { - char* buff = readline(promptForIndentionLevel(openBrackets).c_str()); - isEmpty = !(buff && *buff); - if (!isEmpty) - { - cmd += string(buff); - cmd += " "; - free(buff); - int open = count(cmd.begin(), cmd.end(), '{'); - open += count(cmd.begin(), cmd.end(), '('); - int closed = count(cmd.begin(), cmd.end(), '}'); - closed += count(cmd.begin(), cmd.end(), ')'); - openBrackets = open - closed; - } - } while (openBrackets > 0); - - if (!isEmpty) - { - add_history(cmd.c_str()); - auto value = m_engine.eval(cmd.c_str()); - string result = m_printer.prettyPrint(value).cstr(); - cout << result << endl; - } -} - -std::string JSConsole::promptForIndentionLevel(int _i) const -{ - if (_i == 0) - return "> "; - - return string((_i + 1) * 2, ' '); -} +#include "JSConsole.h" diff --git a/libjsconsole/JSConsole.h b/libjsconsole/JSConsole.h index 2e5144a5d..50f6d6ae5 100644 --- a/libjsconsole/JSConsole.h +++ b/libjsconsole/JSConsole.h @@ -22,32 +22,66 @@ #pragma once -#include -#include - -namespace dev { class WebThreeStubServer; } -namespace jsonrpc { class AbstractServerConnector; } +#include +// TODO! make readline optional! +#include +#include namespace dev { namespace eth { -class AccountHolder; - +template class JSConsole { public: - JSConsole(WebThreeDirect& _web3, std::shared_ptr const& _accounts); - void readExpression() const; + JSConsole(): m_engine(Engine()), m_printer(Printer(m_engine)) {} + ~JSConsole() {} + + void readExpression() const + { + std::string cmd = ""; + g_logPost = [](std::string const& a, char const*) { std::cout << "\r \r" << a << std::endl << std::flush; rl_forced_update_display(); }; + + bool isEmpty = true; + int openBrackets = 0; + do { + char* buff = readline(promptForIndentionLevel(openBrackets).c_str()); + isEmpty = !(buff && *buff); + if (!isEmpty) + { + cmd += std::string(buff); + cmd += " "; + free(buff); + int open = std::count(cmd.begin(), cmd.end(), '{'); + open += std::count(cmd.begin(), cmd.end(), '('); + int closed = std::count(cmd.begin(), cmd.end(), '}'); + closed += std::count(cmd.begin(), cmd.end(), ')'); + openBrackets = open - closed; + } + } while (openBrackets > 0); + + if (!isEmpty) + { + add_history(cmd.c_str()); + auto value = m_engine.eval(cmd.c_str()); + std::string result = m_printer.prettyPrint(value).cstr(); + std::cout << result << std::endl; + } + } + +protected: + Engine m_engine; + Printer m_printer; -private: - std::string promptForIndentionLevel(int _i) const; + virtual std::string promptForIndentionLevel(int _i) const + { + if (_i == 0) + return "> "; - JSV8Engine m_engine; - JSV8Printer m_printer; - std::unique_ptr m_jsonrpcServer; - std::unique_ptr m_jsonrpcConnector; + return std::string((_i + 1) * 2, ' '); + } }; } diff --git a/libjsconsole/JSLocalConsole.cpp b/libjsconsole/JSLocalConsole.cpp new file mode 100644 index 000000000..04c6104a6 --- /dev/null +++ b/libjsconsole/JSLocalConsole.cpp @@ -0,0 +1,34 @@ +/* + 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 JSLocalConsole.cpp + * @author Marek Kotewicz + * @date 2015 + * Ethereum client. + */ + +#include +#include "JSLocalConsole.h" +#include "JSV8Connector.h" + +using namespace std; +using namespace dev; +using namespace dev::eth; + +JSLocalConsole::JSLocalConsole() +{ + m_jsonrpcConnector.reset(new JSV8Connector(m_engine)); +} diff --git a/libjsconsole/JSLocalConsole.h b/libjsconsole/JSLocalConsole.h new file mode 100644 index 000000000..48922faee --- /dev/null +++ b/libjsconsole/JSLocalConsole.h @@ -0,0 +1,50 @@ +/* + 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 JSLocalConsole.h + * @author Marek Kotewicz + * @date 2015 + * Ethereum client. + */ + +#pragma once + +#include +#include +#include "JSConsole.h" + +class WebThreeStubServer; +namespace jsonrpc { class AbstractServerConnector; } + +namespace dev +{ +namespace eth +{ + +class JSLocalConsole: public JSConsole +{ +public: + JSLocalConsole(); + virtual ~JSLocalConsole() {} + + jsonrpc::AbstractServerConnector* connector() { return m_jsonrpcConnector.get(); } + +private: + std::unique_ptr m_jsonrpcConnector; +}; + +} +} diff --git a/libjsconsole/JSRemoteConsole.cpp b/libjsconsole/JSRemoteConsole.cpp new file mode 100644 index 000000000..b42c5b340 --- /dev/null +++ b/libjsconsole/JSRemoteConsole.cpp @@ -0,0 +1,23 @@ +/* + 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 JSRemoteConsole.cpp + * @author Marek Kotewicz + * @date 2015 + * Ethereum client. + */ + +#include "JSRemoteConsole.h" diff --git a/libjsconsole/JSRemoteConsole.h b/libjsconsole/JSRemoteConsole.h new file mode 100644 index 000000000..2baf516f6 --- /dev/null +++ b/libjsconsole/JSRemoteConsole.h @@ -0,0 +1,48 @@ +/* + 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 JSRemoteConsole.h + * @author Marek Kotewicz + * @date 2015 + * Ethereum client. + */ + +#pragma once + +#include +#include +#include "JSV8RemoteConnector.h" +#include "JSConsole.h" + +namespace dev +{ +namespace eth +{ + +class JSRemoteConsole: public JSConsole +{ + +public: + JSRemoteConsole(std::string _url): m_connector(m_engine, _url) {} + virtual ~JSRemoteConsole() {} + +private: + JSV8RemoteConnector m_connector; + +}; + +} +} diff --git a/libjsconsole/JSV8Connector.h b/libjsconsole/JSV8Connector.h index 98cef4c2c..34c38fed1 100644 --- a/libjsconsole/JSV8Connector.h +++ b/libjsconsole/JSV8Connector.h @@ -43,7 +43,7 @@ public: bool SendResponse(std::string const& _response, void* _addInfo = nullptr); // implement JSV8RPC interface - void onSend(char const* payload); + void onSend(char const* _payload); }; } diff --git a/libjsconsole/JSV8RemoteConnector.cpp b/libjsconsole/JSV8RemoteConnector.cpp new file mode 100644 index 000000000..72e64faae --- /dev/null +++ b/libjsconsole/JSV8RemoteConnector.cpp @@ -0,0 +1,20 @@ +// +// Created by Marek Kotewicz on 15/06/15. +// + +#include "JSV8RemoteConnector.h" + +using namespace std; +using namespace dev; +using namespace dev::eth; + +void JSV8RemoteConnector::onSend(char const* _payload) +{ + m_request.setUrl(m_url); + m_request.setBody(_payload); + long code; + string response; + tie(code, response) = m_request.post(); + (void)code; + m_lastResponse = response.c_str(); +} diff --git a/libjsconsole/JSV8RemoteConnector.h b/libjsconsole/JSV8RemoteConnector.h new file mode 100644 index 000000000..5d28094ad --- /dev/null +++ b/libjsconsole/JSV8RemoteConnector.h @@ -0,0 +1,32 @@ +// +// Created by Marek Kotewicz on 15/06/15. +// + +#pragma once + +#include +#include +#include "CURLRequest.h" + +namespace dev +{ +namespace eth +{ + +class JSV8RemoteConnector : public JSV8RPC +{ + +public: + JSV8RemoteConnector(JSV8Engine const& _engine, std::string _url): JSV8RPC(_engine), m_url(_url) {} + virtual ~JSV8RemoteConnector() {} + + // implement JSV8RPC interface + void onSend(char const* _payload); + +private: + std::string m_url; + CURLRequest m_request; +}; + +} +} diff --git a/libjsengine/JSResources.cmake b/libjsengine/JSResources.cmake index d4370a8da..15e788778 100644 --- a/libjsengine/JSResources.cmake +++ b/libjsengine/JSResources.cmake @@ -1,8 +1,9 @@ set(web3 "${CMAKE_CURRENT_LIST_DIR}/../libjsqrc/ethereumjs/dist/web3.js") +set(admin "${CMAKE_CURRENT_LIST_DIR}/../libjsqrc/admin.js") set(pretty_print "${CMAKE_CURRENT_LIST_DIR}/PrettyPrint.js") set(common "${CMAKE_CURRENT_LIST_DIR}/Common.js") set(ETH_RESOURCE_NAME "JSEngineResources") set(ETH_RESOURCE_LOCATION "${CMAKE_CURRENT_BINARY_DIR}") -set(ETH_RESOURCES "web3" "pretty_print" "common") +set(ETH_RESOURCES "web3" "pretty_print" "common" "admin") diff --git a/libjsengine/JSV8Engine.cpp b/libjsengine/JSV8Engine.cpp index 4e06f0f65..ebf0a0e72 100644 --- a/libjsengine/JSV8Engine.cpp +++ b/libjsengine/JSV8Engine.cpp @@ -143,9 +143,11 @@ JSV8Engine::JSV8Engine(): m_scope(new JSV8Scope()) JSEngineResources resources; string common = resources.loadResourceAsString("common"); string web3 = resources.loadResourceAsString("web3"); + string admin = resources.loadResourceAsString("admin"); eval(common.c_str()); eval(web3.c_str()); eval("web3 = require('web3');"); + eval(admin.c_str()); } JSV8Engine::~JSV8Engine() diff --git a/libjsengine/JSV8Engine.h b/libjsengine/JSV8Engine.h index 56459c5d0..563642d73 100644 --- a/libjsengine/JSV8Engine.h +++ b/libjsengine/JSV8Engine.h @@ -22,7 +22,10 @@ #pragma once +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-parameter" #include +#pragma clang diagnostic pop #include "JSEngine.h" namespace dev diff --git a/libjsqrc/admin.js b/libjsqrc/admin.js new file mode 100644 index 000000000..4bd55e74f --- /dev/null +++ b/libjsqrc/admin.js @@ -0,0 +1,120 @@ +web3.admin = {}; +web3.admin.setSessionKey = function(s) { web3.admin.sessionKey = s; }; + +var getSessionKey = function () { return web3.admin.sessionKey; }; + +web3._extend({ + property: 'admin', + methods: [new web3._extend.Method({ + name: 'web3.setVerbosity', + call: 'admin_web3_setVerbosity', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'net.start', + call: 'admin_net_start', + inputFormatter: [getSessionKey], + params: 1 + }), new web3._extend.Method({ + name: 'net.stop', + call: 'admin_net_stop', + inputFormatter: [getSessionKey], + params: 1 + }), new web3._extend.Method({ + name: 'net.connect', + call: 'admin_net_connect', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'net.peers', + call: 'admin_net_peers', + inputFormatter: [getSessionKey], + params: 1 + }), new web3._extend.Method({ + name: 'eth.blockQueueStatus', + call: 'admin_eth_blockQueueStatus', + inputFormatter: [getSessionKey], + params: 1 + }), new web3._extend.Method({ + name: 'eth.setAskPrice', + call: 'admin_eth_setAskPrice', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.setBidPrice', + call: 'admin_eth_setBidPrice', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.setReferencePrice', + call: 'admin_eth_setReferencePrice', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.setPriority', + call: 'admin_eth_setPriority', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.setMining', + call: 'admin_eth_setMining', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.findBlock', + call: 'admin_eth_findBlock', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.blockQueueFirstUnknown', + call: 'admin_eth_blockQueueFirstUnknown', + inputFormatter: [getSessionKey], + params: 1 + }), new web3._extend.Method({ + name: 'eth.blockQueueRetryUnknown', + call: 'admin_eth_blockQueueRetryUnknown', + inputFormatter: [getSessionKey], + params: 1 + }), new web3._extend.Method({ + name: 'eth.allAccounts', + call: 'admin_eth_allAccounts', + inputFormatter: [getSessionKey], + params: 1 + }), new web3._extend.Method({ + name: 'eth.newAccount', + call: 'admin_eth_newAccount', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.setSigningKey', + call: 'admin_eth_setSigningKey', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.setMiningBenefactor', + call: 'admin_eth_setMiningBenefactor', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.inspect', + call: 'admin_eth_inspect', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.reprocess', + call: 'admin_eth_reprocess', + inputFormatter: [null, getSessionKey], + params: 2 + }), new web3._extend.Method({ + name: 'eth.vmTrace', + call: 'admin_eth_vmTrace', + inputFormatter: [null, null, getSessionKey], + params: 3 + }), new web3._extend.Method({ + name: 'eth.getReceiptByHashAndIndex', + call: 'admin_eth_getReceiptByHashAndIndex', + inputFormatter: [null, null, getSessionKey], + params: 3 + })] +}); + diff --git a/libjsqrc/ethereumjs/LICENSE b/libjsqrc/ethereumjs/LICENSE index 0f187b873..29a99abb4 100644 --- a/libjsqrc/ethereumjs/LICENSE +++ b/libjsqrc/ethereumjs/LICENSE @@ -1,14 +1,14 @@ -This file is part of ethereum.js. +This file is part of web3.js. -ethereum.js is free software: you can redistribute it and/or modify +web3.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, +web3.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 . \ No newline at end of file +along with web3.js. If not, see . diff --git a/libjsqrc/ethereumjs/README.md b/libjsqrc/ethereumjs/README.md index 7a1c651fd..8abd8821d 100644 --- a/libjsqrc/ethereumjs/README.md +++ b/libjsqrc/ethereumjs/README.md @@ -108,7 +108,7 @@ eth -j [travis-url]: https://travis-ci.org/ethereum/web3.js [dep-image]: https://david-dm.org/ethereum/web3.js.svg [dep-url]: https://david-dm.org/ethereum/web3.js -[dep-dev-image]: https://david-dm.org/ethereum/web.js/dev-status.svg +[dep-dev-image]: https://david-dm.org/ethereum/web3.js/dev-status.svg [dep-dev-url]: https://david-dm.org/ethereum/web3.js#info=devDependencies [coveralls-image]: https://coveralls.io/repos/ethereum/web3.js/badge.svg?branch=master [coveralls-url]: https://coveralls.io/r/ethereum/web3.js?branch=master diff --git a/libjsqrc/ethereumjs/bower.json b/libjsqrc/ethereumjs/bower.json index eacbb4509..cb63bd076 100644 --- a/libjsqrc/ethereumjs/bower.json +++ b/libjsqrc/ethereumjs/bower.json @@ -1,7 +1,7 @@ { "name": "web3", "namespace": "ethereum", - "version": "0.5.0", + "version": "0.6.0", "description": "Ethereum Compatible JavaScript API", "main": [ "./dist/web3.js", diff --git a/libjsqrc/ethereumjs/dist/web3-light.js b/libjsqrc/ethereumjs/dist/web3-light.js new file mode 100644 index 000000000..a57cac292 --- /dev/null +++ b/libjsqrc/ethereumjs/dist/web3-light.js @@ -0,0 +1,5683 @@ +require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o. +*/ +/** + * @file coder.js + * @author Marek Kotewicz + * @date 2015 + */ + +var BigNumber = require('bignumber.js'); +var utils = require('../utils/utils'); +var f = require('./formatters'); +var SolidityParam = require('./param'); + +/** + * Should be used to check if a type is an array type + * + * @method isArrayType + * @param {String} type + * @return {Bool} true is the type is an array, otherwise false + */ +var isArrayType = function (type) { + return type.slice(-2) === '[]'; +}; + +/** + * SolidityType prototype is used to encode/decode solidity params of certain type + */ +var SolidityType = function (config) { + this._name = config.name; + this._match = config.match; + this._mode = config.mode; + this._inputFormatter = config.inputFormatter; + this._outputFormatter = config.outputFormatter; +}; + +/** + * Should be used to determine if this SolidityType do match given type + * + * @method isType + * @param {String} name + * @return {Bool} true if type match this SolidityType, otherwise false + */ +SolidityType.prototype.isType = function (name) { + if (this._match === 'strict') { + return this._name === name || (name.indexOf(this._name) === 0 && name.slice(this._name.length) === '[]'); + } else if (this._match === 'prefix') { + // TODO better type detection! + return name.indexOf(this._name) === 0; + } +}; + +/** + * Should be used to transform plain param to SolidityParam object + * + * @method formatInput + * @param {Object} param - plain object, or an array of objects + * @param {Bool} arrayType - true if a param should be encoded as an array + * @return {SolidityParam} encoded param wrapped in SolidityParam object + */ +SolidityType.prototype.formatInput = function (param, arrayType) { + if (utils.isArray(param) && arrayType) { // TODO: should fail if this two are not the same + var self = this; + return param.map(function (p) { + return self._inputFormatter(p); + }).reduce(function (acc, current) { + return acc.combine(current); + }, f.formatInputInt(param.length)).withOffset(32); + } + return this._inputFormatter(param); +}; + +/** + * Should be used to transoform SolidityParam to plain param + * + * @method formatOutput + * @param {SolidityParam} byteArray + * @param {Bool} arrayType - true if a param should be decoded as an array + * @return {Object} plain decoded param + */ +SolidityType.prototype.formatOutput = function (param, arrayType) { + if (arrayType) { + // let's assume, that we solidity will never return long arrays :P + var result = []; + var length = new BigNumber(param.dynamicPart().slice(0, 64), 16); + for (var i = 0; i < length * 64; i += 64) { + result.push(this._outputFormatter(new SolidityParam(param.dynamicPart().substr(i + 64, 64)))); + } + return result; + } + return this._outputFormatter(param); +}; + +/** + * Should be used to slice single param from bytes + * + * @method sliceParam + * @param {String} bytes + * @param {Number} index of param to slice + * @param {String} type + * @returns {SolidityParam} param + */ +SolidityType.prototype.sliceParam = function (bytes, index, type) { + if (this._mode === 'bytes') { + return SolidityParam.decodeBytes(bytes, index); + } else if (isArrayType(type)) { + return SolidityParam.decodeArray(bytes, index); + } + return SolidityParam.decodeParam(bytes, index); +}; + +/** + * SolidityCoder prototype should be used to encode/decode solidity params of any type + */ +var SolidityCoder = function (types) { + this._types = types; +}; + +/** + * This method should be used to transform type to SolidityType + * + * @method _requireType + * @param {String} type + * @returns {SolidityType} + * @throws {Error} throws if no matching type is found + */ +SolidityCoder.prototype._requireType = function (type) { + var solidityType = this._types.filter(function (t) { + return t.isType(type); + })[0]; + + if (!solidityType) { + throw Error('invalid solidity type!: ' + type); + } + + return solidityType; +}; + +/** + * Should be used to transform plain param of given type to SolidityParam + * + * @method _formatInput + * @param {String} type of param + * @param {Object} plain param + * @return {SolidityParam} + */ +SolidityCoder.prototype._formatInput = function (type, param) { + return this._requireType(type).formatInput(param, isArrayType(type)); +}; + +/** + * Should be used to encode plain param + * + * @method encodeParam + * @param {String} type + * @param {Object} plain param + * @return {String} encoded plain param + */ +SolidityCoder.prototype.encodeParam = function (type, param) { + return this._formatInput(type, param).encode(); +}; + +/** + * Should be used to encode list of params + * + * @method encodeParams + * @param {Array} types + * @param {Array} params + * @return {String} encoded list of params + */ +SolidityCoder.prototype.encodeParams = function (types, params) { + var self = this; + var solidityParams = types.map(function (type, index) { + return self._formatInput(type, params[index]); + }); + + return SolidityParam.encodeList(solidityParams); +}; + +/** + * Should be used to decode bytes to plain param + * + * @method decodeParam + * @param {String} type + * @param {String} bytes + * @return {Object} plain param + */ +SolidityCoder.prototype.decodeParam = function (type, bytes) { + return this.decodeParams([type], bytes)[0]; +}; + +/** + * Should be used to decode list of params + * + * @method decodeParam + * @param {Array} types + * @param {String} bytes + * @return {Array} array of plain params + */ +SolidityCoder.prototype.decodeParams = function (types, bytes) { + var self = this; + return types.map(function (type, index) { + var solidityType = self._requireType(type); + var p = solidityType.sliceParam(bytes, index, type); + return solidityType.formatOutput(p, isArrayType(type)); + }); +}; + +var coder = new SolidityCoder([ + new SolidityType({ + name: 'address', + match: 'strict', + mode: 'value', + inputFormatter: f.formatInputInt, + outputFormatter: f.formatOutputAddress + }), + new SolidityType({ + name: 'bool', + match: 'strict', + mode: 'value', + inputFormatter: f.formatInputBool, + outputFormatter: f.formatOutputBool + }), + new SolidityType({ + name: 'int', + match: 'prefix', + mode: 'value', + inputFormatter: f.formatInputInt, + outputFormatter: f.formatOutputInt, + }), + new SolidityType({ + name: 'uint', + match: 'prefix', + mode: 'value', + inputFormatter: f.formatInputInt, + outputFormatter: f.formatOutputUInt + }), + new SolidityType({ + name: 'bytes', + match: 'strict', + mode: 'bytes', + inputFormatter: f.formatInputDynamicBytes, + outputFormatter: f.formatOutputDynamicBytes + }), + new SolidityType({ + name: 'bytes', + match: 'prefix', + mode: 'value', + inputFormatter: f.formatInputBytes, + outputFormatter: f.formatOutputBytes + }), + new SolidityType({ + name: 'real', + match: 'prefix', + mode: 'value', + inputFormatter: f.formatInputReal, + outputFormatter: f.formatOutputReal + }), + new SolidityType({ + name: 'ureal', + match: 'prefix', + mode: 'value', + inputFormatter: f.formatInputReal, + outputFormatter: f.formatOutputUReal + }) +]); + +module.exports = coder; + + +},{"../utils/utils":7,"./formatters":2,"./param":3,"bignumber.js":"bignumber.js"}],2:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** + * @file formatters.js + * @author Marek Kotewicz + * @date 2015 + */ + +var BigNumber = require('bignumber.js'); +var utils = require('../utils/utils'); +var c = require('../utils/config'); +var SolidityParam = require('./param'); + + +/** + * Formats input value to byte representation of int + * If value is negative, return it's two's complement + * If the value is floating point, round it down + * + * @method formatInputInt + * @param {String|Number|BigNumber} value that needs to be formatted + * @returns {SolidityParam} + */ +var formatInputInt = function (value) { + var padding = c.ETH_PADDING * 2; + BigNumber.config(c.ETH_BIGNUMBER_ROUNDING_MODE); + var result = utils.padLeft(utils.toTwosComplement(value).round().toString(16), padding); + return new SolidityParam(result); +}; + +/** + * Formats input value to byte representation of string + * + * @method formatInputBytes + * @param {String} + * @returns {SolidityParam} + */ +var formatInputBytes = function (value) { + var result = utils.fromAscii(value, c.ETH_PADDING).substr(2); + return new SolidityParam(result); +}; + +/** + * Formats input value to byte representation of string + * + * @method formatInputDynamicBytes + * @param {String} + * @returns {SolidityParam} + */ +var formatInputDynamicBytes = function (value) { + var result = utils.fromAscii(value, c.ETH_PADDING).substr(2); + return new SolidityParam(formatInputInt(value.length).value + result, 32); +}; + +/** + * Formats input value to byte representation of bool + * + * @method formatInputBool + * @param {Boolean} + * @returns {SolidityParam} + */ +var formatInputBool = function (value) { + var result = '000000000000000000000000000000000000000000000000000000000000000' + (value ? '1' : '0'); + return new SolidityParam(result); +}; + +/** + * Formats input value to byte representation of real + * Values are multiplied by 2^m and encoded as integers + * + * @method formatInputReal + * @param {String|Number|BigNumber} + * @returns {SolidityParam} + */ +var formatInputReal = function (value) { + return formatInputInt(new BigNumber(value).times(new BigNumber(2).pow(128))); +}; + +/** + * Check if input value is negative + * + * @method signedIsNegative + * @param {String} value is hex format + * @returns {Boolean} true if it is negative, otherwise false + */ +var signedIsNegative = function (value) { + return (new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1'; +}; + +/** + * Formats right-aligned output bytes to int + * + * @method formatOutputInt + * @param {SolidityParam} param + * @returns {BigNumber} right-aligned output bytes formatted to big number + */ +var formatOutputInt = function (param) { + var value = param.staticPart() || "0"; + + // check if it's negative number + // it it is, return two's complement + if (signedIsNegative(value)) { + return new BigNumber(value, 16).minus(new BigNumber('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 16)).minus(1); + } + return new BigNumber(value, 16); +}; + +/** + * Formats right-aligned output bytes to uint + * + * @method formatOutputUInt + * @param {SolidityParam} + * @returns {BigNumeber} right-aligned output bytes formatted to uint + */ +var formatOutputUInt = function (param) { + var value = param.staticPart() || "0"; + return new BigNumber(value, 16); +}; + +/** + * Formats right-aligned output bytes to real + * + * @method formatOutputReal + * @param {SolidityParam} + * @returns {BigNumber} input bytes formatted to real + */ +var formatOutputReal = function (param) { + return formatOutputInt(param).dividedBy(new BigNumber(2).pow(128)); +}; + +/** + * Formats right-aligned output bytes to ureal + * + * @method formatOutputUReal + * @param {SolidityParam} + * @returns {BigNumber} input bytes formatted to ureal + */ +var formatOutputUReal = function (param) { + return formatOutputUInt(param).dividedBy(new BigNumber(2).pow(128)); +}; + +/** + * Should be used to format output bool + * + * @method formatOutputBool + * @param {SolidityParam} + * @returns {Boolean} right-aligned input bytes formatted to bool + */ +var formatOutputBool = function (param) { + return param.staticPart() === '0000000000000000000000000000000000000000000000000000000000000001' ? true : false; +}; + +/** + * Should be used to format output string + * + * @method formatOutputBytes + * @param {SolidityParam} left-aligned hex representation of string + * @returns {String} ascii string + */ +var formatOutputBytes = function (param) { + // length might also be important! + return utils.toAscii(param.staticPart()); +}; + +/** + * Should be used to format output string + * + * @method formatOutputDynamicBytes + * @param {SolidityParam} left-aligned hex representation of string + * @returns {String} ascii string + */ +var formatOutputDynamicBytes = function (param) { + // length might also be important! + return utils.toAscii(param.dynamicPart().slice(64)); +}; + +/** + * Should be used to format output address + * + * @method formatOutputAddress + * @param {SolidityParam} right-aligned input bytes + * @returns {String} address + */ +var formatOutputAddress = function (param) { + var value = param.staticPart(); + return "0x" + value.slice(value.length - 40, value.length); +}; + +module.exports = { + formatInputInt: formatInputInt, + formatInputBytes: formatInputBytes, + formatInputDynamicBytes: formatInputDynamicBytes, + formatInputBool: formatInputBool, + formatInputReal: formatInputReal, + formatOutputInt: formatOutputInt, + formatOutputUInt: formatOutputUInt, + formatOutputReal: formatOutputReal, + formatOutputUReal: formatOutputUReal, + formatOutputBool: formatOutputBool, + formatOutputBytes: formatOutputBytes, + formatOutputDynamicBytes: formatOutputDynamicBytes, + formatOutputAddress: formatOutputAddress +}; + + +},{"../utils/config":5,"../utils/utils":7,"./param":3,"bignumber.js":"bignumber.js"}],3:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** + * @file param.js + * @author Marek Kotewicz + * @date 2015 + */ + +var utils = require('../utils/utils'); + +/** + * SolidityParam object prototype. + * Should be used when encoding, decoding solidity bytes + */ +var SolidityParam = function (value, offset) { + this.value = value || ''; + this.offset = offset; // offset in bytes +}; + +/** + * This method should be used to get length of params's dynamic part + * + * @method dynamicPartLength + * @returns {Number} length of dynamic part (in bytes) + */ +SolidityParam.prototype.dynamicPartLength = function () { + return this.dynamicPart().length / 2; +}; + +/** + * This method should be used to create copy of solidity param with different offset + * + * @method withOffset + * @param {Number} offset length in bytes + * @returns {SolidityParam} new solidity param with applied offset + */ +SolidityParam.prototype.withOffset = function (offset) { + return new SolidityParam(this.value, offset); +}; + +/** + * This method should be used to combine solidity params together + * eg. when appending an array + * + * @method combine + * @param {SolidityParam} param with which we should combine + * @param {SolidityParam} result of combination + */ +SolidityParam.prototype.combine = function (param) { + return new SolidityParam(this.value + param.value); +}; + +/** + * This method should be called to check if param has dynamic size. + * If it has, it returns true, otherwise false + * + * @method isDynamic + * @returns {Boolean} + */ +SolidityParam.prototype.isDynamic = function () { + return this.value.length > 64 || this.offset !== undefined; +}; + +/** + * This method should be called to transform offset to bytes + * + * @method offsetAsBytes + * @returns {String} bytes representation of offset + */ +SolidityParam.prototype.offsetAsBytes = function () { + return !this.isDynamic() ? '' : utils.padLeft(utils.toTwosComplement(this.offset).toString(16), 64); +}; + +/** + * This method should be called to get static part of param + * + * @method staticPart + * @returns {String} offset if it is a dynamic param, otherwise value + */ +SolidityParam.prototype.staticPart = function () { + if (!this.isDynamic()) { + return this.value; + } + return this.offsetAsBytes(); +}; + +/** + * This method should be called to get dynamic part of param + * + * @method dynamicPart + * @returns {String} returns a value if it is a dynamic param, otherwise empty string + */ +SolidityParam.prototype.dynamicPart = function () { + return this.isDynamic() ? this.value : ''; +}; + +/** + * This method should be called to encode param + * + * @method encode + * @returns {String} + */ +SolidityParam.prototype.encode = function () { + return this.staticPart() + this.dynamicPart(); +}; + +/** + * This method should be called to encode array of params + * + * @method encodeList + * @param {Array[SolidityParam]} params + * @returns {String} + */ +SolidityParam.encodeList = function (params) { + + // updating offsets + var totalOffset = params.length * 32; + var offsetParams = params.map(function (param) { + if (!param.isDynamic()) { + return param; + } + var offset = totalOffset; + totalOffset += param.dynamicPartLength(); + return param.withOffset(offset); + }); + + // encode everything! + return offsetParams.reduce(function (result, param) { + return result + param.dynamicPart(); + }, offsetParams.reduce(function (result, param) { + return result + param.staticPart(); + }, '')); +}; + +/** + * This method should be used to decode plain (static) solidity param at given index + * + * @method decodeParam + * @param {String} bytes + * @param {Number} index + * @returns {SolidityParam} + */ +SolidityParam.decodeParam = function (bytes, index) { + index = index || 0; + return new SolidityParam(bytes.substr(index * 64, 64)); +}; + +/** + * This method should be called to get offset value from bytes at given index + * + * @method getOffset + * @param {String} bytes + * @param {Number} index + * @returns {Number} offset as number + */ +var getOffset = function (bytes, index) { + // we can do this cause offset is rather small + return parseInt('0x' + bytes.substr(index * 64, 64)); +}; + +/** + * This method should be called to decode solidity bytes param at given index + * + * @method decodeBytes + * @param {String} bytes + * @param {Number} index + * @returns {SolidityParam} + */ +SolidityParam.decodeBytes = function (bytes, index) { + index = index || 0; + //TODO add support for strings longer than 32 bytes + //var length = parseInt('0x' + bytes.substr(offset * 64, 64)); + + var offset = getOffset(bytes, index); + + // 2 * , cause we also parse length + return new SolidityParam(bytes.substr(offset * 2, 2 * 64), 0); +}; + +/** + * This method should be used to decode solidity array at given index + * + * @method decodeArray + * @param {String} bytes + * @param {Number} index + * @returns {SolidityParam} + */ +SolidityParam.decodeArray = function (bytes, index) { + index = index || 0; + var offset = getOffset(bytes, index); + var length = parseInt('0x' + bytes.substr(offset * 2, 64)); + return new SolidityParam(bytes.substr(offset * 2, (length + 1) * 64), 0); +}; + +module.exports = SolidityParam; + + +},{"../utils/utils":7}],4:[function(require,module,exports){ +'use strict'; + +// go env doesn't have and need XMLHttpRequest +if (typeof XMLHttpRequest === 'undefined') { + exports.XMLHttpRequest = {}; +} else { + exports.XMLHttpRequest = XMLHttpRequest; // jshint ignore:line +} + + +},{}],5:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file config.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +/** + * Utils + * + * @module utils + */ + +/** + * Utility functions + * + * @class [utils] config + * @constructor + */ + +/// required to define ETH_BIGNUMBER_ROUNDING_MODE +var BigNumber = require('bignumber.js'); + +var ETH_UNITS = [ + 'wei', + 'kwei', + 'Mwei', + 'Gwei', + 'szabo', + 'finney', + 'femtoether', + 'picoether', + 'nanoether', + 'microether', + 'milliether', + 'nano', + 'micro', + 'milli', + 'ether', + 'grand', + 'Mether', + 'Gether', + 'Tether', + 'Pether', + 'Eether', + 'Zether', + 'Yether', + 'Nether', + 'Dether', + 'Vether', + 'Uether' +]; + +module.exports = { + ETH_PADDING: 32, + ETH_SIGNATURE_LENGTH: 4, + ETH_UNITS: ETH_UNITS, + ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }, + ETH_POLLING_TIMEOUT: 1000/2, + defaultBlock: 'latest', + defaultAccount: undefined +}; + + +},{"bignumber.js":"bignumber.js"}],6:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** + * @file sha3.js + * @author Marek Kotewicz + * @date 2015 + */ + +var utils = require('./utils'); +var sha3 = require('crypto-js/sha3'); + +module.exports = function (str, isNew) { + if (str.substr(0, 2) === '0x' && !isNew) { + console.warn('requirement of using web3.fromAscii before sha3 is deprecated'); + console.warn('new usage: \'web3.sha3("hello")\''); + console.warn('see https://github.com/ethereum/web3.js/pull/205'); + console.warn('if you need to hash hex value, you can do \'sha3("0xfff", true)\''); + str = utils.toAscii(str); + } + + return sha3(str, { + outputLength: 256 + }).toString(); +}; + + +},{"./utils":7,"crypto-js/sha3":33}],7:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** + * @file utils.js + * @author Marek Kotewicz + * @date 2015 + */ + +/** + * Utils + * + * @module utils + */ + +/** + * Utility functions + * + * @class [utils] utils + * @constructor + */ + +var BigNumber = require('bignumber.js'); + +var unitMap = { + 'wei': '1', + 'kwei': '1000', + 'ada': '1000', + 'femtoether': '1000', + 'mwei': '1000000', + 'babbage': '1000000', + 'picoether': '1000000', + 'gwei': '1000000000', + 'shannon': '1000000000', + 'nanoether': '1000000000', + 'nano': '1000000000', + 'szabo': '1000000000000', + 'microether': '1000000000000', + 'micro': '1000000000000', + 'finney': '1000000000000000', + 'milliether': '1000000000000000', + 'milli': '1000000000000000', + 'ether': '1000000000000000000', + 'kether': '1000000000000000000000', + 'grand': '1000000000000000000000', + 'einstein': '1000000000000000000000', + 'mether': '1000000000000000000000000', + 'gether': '1000000000000000000000000000', + 'tether': '1000000000000000000000000000000' +}; + +/** + * Should be called to pad string to expected length + * + * @method padLeft + * @param {String} string to be padded + * @param {Number} characters that result string should have + * @param {String} sign, by default 0 + * @returns {String} right aligned string + */ +var padLeft = function (string, chars, sign) { + return new Array(chars - string.length + 1).join(sign ? sign : "0") + string; +}; + +/** + * Should be called to get sting from it's hex representation + * + * @method toAscii + * @param {String} string in hex + * @returns {String} ascii string representation of hex value + */ +var toAscii = function(hex) { +// Find termination + var str = ""; + var i = 0, l = hex.length; + if (hex.substring(0, 2) === '0x') { + i = 2; + } + for (; i < l; i+=2) { + var code = parseInt(hex.substr(i, 2), 16); + if (code === 0) { + break; + } + + str += String.fromCharCode(code); + } + + return str; +}; + +/** + * Shold be called to get hex representation (prefixed by 0x) of ascii string + * + * @method toHexNative + * @param {String} string + * @returns {String} hex representation of input string + */ +var toHexNative = function(str) { + var hex = ""; + for(var i = 0; i < str.length; i++) { + var n = str.charCodeAt(i).toString(16); + hex += n.length < 2 ? '0' + n : n; + } + + return hex; +}; + +/** + * Shold be called to get hex representation (prefixed by 0x) of ascii string + * + * @method fromAscii + * @param {String} string + * @param {Number} optional padding + * @returns {String} hex representation of input string + */ +var fromAscii = function(str, pad) { + pad = pad === undefined ? 0 : pad; + var hex = toHexNative(str); + while (hex.length < pad*2) + hex += "00"; + return "0x" + hex; +}; + +/** + * Should be used to create full function/event name from json abi + * + * @method transformToFullName + * @param {Object} json-abi + * @return {String} full fnction/event name + */ +var transformToFullName = function (json) { + if (json.name.indexOf('(') !== -1) { + return json.name; + } + + var typeName = json.inputs.map(function(i){return i.type; }).join(); + return json.name + '(' + typeName + ')'; +}; + +/** + * Should be called to get display name of contract function + * + * @method extractDisplayName + * @param {String} name of function/event + * @returns {String} display name for function/event eg. multiply(uint256) -> multiply + */ +var extractDisplayName = function (name) { + var length = name.indexOf('('); + return length !== -1 ? name.substr(0, length) : name; +}; + +/// @returns overloaded part of function/event name +var extractTypeName = function (name) { + /// TODO: make it invulnerable + var length = name.indexOf('('); + return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : ""; +}; + +/** + * Converts value to it's decimal representation in string + * + * @method toDecimal + * @param {String|Number|BigNumber} + * @return {String} + */ +var toDecimal = function (value) { + return toBigNumber(value).toNumber(); +}; + +/** + * Converts value to it's hex representation + * + * @method fromDecimal + * @param {String|Number|BigNumber} + * @return {String} + */ +var fromDecimal = function (value) { + var number = toBigNumber(value); + var result = number.toString(16); + + return number.lessThan(0) ? '-0x' + result.substr(1) : '0x' + result; +}; + +/** + * Auto converts any given value into it's hex representation. + * + * And even stringifys objects before. + * + * @method toHex + * @param {String|Number|BigNumber|Object} + * @return {String} + */ +var toHex = function (val) { + /*jshint maxcomplexity:7 */ + + if (isBoolean(val)) + return fromDecimal(+val); + + if (isBigNumber(val)) + return fromDecimal(val); + + if (isObject(val)) + return fromAscii(JSON.stringify(val)); + + // if its a negative number, pass it through fromDecimal + if (isString(val)) { + if (val.indexOf('-0x') === 0) + return fromDecimal(val); + else if (!isFinite(val)) + return fromAscii(val); + } + + return fromDecimal(val); +}; + +/** + * Returns value of unit in Wei + * + * @method getValueOfUnit + * @param {String} unit the unit to convert to, default ether + * @returns {BigNumber} value of the unit (in Wei) + * @throws error if the unit is not correct:w + */ +var getValueOfUnit = function (unit) { + unit = unit ? unit.toLowerCase() : 'ether'; + var unitValue = unitMap[unit]; + if (unitValue === undefined) { + throw new Error('This unit doesn\'t exists, please use the one of the following units' + JSON.stringify(unitMap, null, 2)); + } + return new BigNumber(unitValue, 10); +}; + +/** + * Takes a number of wei and converts it to any other ether unit. + * + * Possible units are: + * SI Short SI Full Effigy Other + * - kwei femtoether ada + * - mwei picoether babbage + * - gwei nanoether shannon nano + * - -- microether szabo micro + * - -- milliether finney milli + * - ether -- -- + * - kether einstein grand + * - mether + * - gether + * - tether + * + * @method fromWei + * @param {Number|String} number can be a number, number string or a HEX of a decimal + * @param {String} unit the unit to convert to, default ether + * @return {String|Object} When given a BigNumber object it returns one as well, otherwise a number +*/ +var fromWei = function(number, unit) { + var returnValue = toBigNumber(number).dividedBy(getValueOfUnit(unit)); + + return isBigNumber(number) ? returnValue : returnValue.toString(10); +}; + +/** + * Takes a number of a unit and converts it to wei. + * + * Possible units are: + * SI Short SI Full Effigy Other + * - kwei femtoether ada + * - mwei picoether babbage + * - gwei nanoether shannon nano + * - -- microether szabo micro + * - -- milliether finney milli + * - ether -- -- + * - kether einstein grand + * - mether + * - gether + * - tether + * + * @method toWei + * @param {Number|String|BigNumber} number can be a number, number string or a HEX of a decimal + * @param {String} unit the unit to convert from, default ether + * @return {String|Object} When given a BigNumber object it returns one as well, otherwise a number +*/ +var toWei = function(number, unit) { + var returnValue = toBigNumber(number).times(getValueOfUnit(unit)); + + return isBigNumber(number) ? returnValue : returnValue.toString(10); +}; + +/** + * Takes an input and transforms it into an bignumber + * + * @method toBigNumber + * @param {Number|String|BigNumber} a number, string, HEX string or BigNumber + * @return {BigNumber} BigNumber +*/ +var toBigNumber = function(number) { + /*jshint maxcomplexity:5 */ + number = number || 0; + if (isBigNumber(number)) + return number; + + if (isString(number) && (number.indexOf('0x') === 0 || number.indexOf('-0x') === 0)) { + return new BigNumber(number.replace('0x',''), 16); + } + + return new BigNumber(number.toString(10), 10); +}; + +/** + * Takes and input transforms it into bignumber and if it is negative value, into two's complement + * + * @method toTwosComplement + * @param {Number|String|BigNumber} + * @return {BigNumber} + */ +var toTwosComplement = function (number) { + var bigNumber = toBigNumber(number); + if (bigNumber.lessThan(0)) { + return new BigNumber("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16).plus(bigNumber).plus(1); + } + return bigNumber; +}; + +/** + * Checks if the given string is strictly an address + * + * @method isStrictAddress + * @param {String} address the given HEX adress + * @return {Boolean} +*/ +var isStrictAddress = function (address) { + return /^0x[0-9a-f]{40}$/.test(address); +}; + +/** + * Checks if the given string is an address + * + * @method isAddress + * @param {String} address the given HEX adress + * @return {Boolean} +*/ +var isAddress = function (address) { + return /^(0x)?[0-9a-f]{40}$/.test(address); +}; + +/** + * Transforms given string to valid 20 bytes-length addres with 0x prefix + * + * @method toAddress + * @param {String} address + * @return {String} formatted address + */ +var toAddress = function (address) { + if (isStrictAddress(address)) { + return address; + } + + if (/^[0-9a-f]{40}$/.test(address)) { + return '0x' + address; + } + + return '0x' + padLeft(toHex(address).substr(2), 40); +}; + + +/** + * Returns true if object is BigNumber, otherwise false + * + * @method isBigNumber + * @param {Object} + * @return {Boolean} + */ +var isBigNumber = function (object) { + return object instanceof BigNumber || + (object && object.constructor && object.constructor.name === 'BigNumber'); +}; + +/** + * Returns true if object is string, otherwise false + * + * @method isString + * @param {Object} + * @return {Boolean} + */ +var isString = function (object) { + return typeof object === 'string' || + (object && object.constructor && object.constructor.name === 'String'); +}; + +/** + * Returns true if object is function, otherwise false + * + * @method isFunction + * @param {Object} + * @return {Boolean} + */ +var isFunction = function (object) { + return typeof object === 'function'; +}; + +/** + * Returns true if object is Objet, otherwise false + * + * @method isObject + * @param {Object} + * @return {Boolean} + */ +var isObject = function (object) { + return typeof object === 'object'; +}; + +/** + * Returns true if object is boolean, otherwise false + * + * @method isBoolean + * @param {Object} + * @return {Boolean} + */ +var isBoolean = function (object) { + return typeof object === 'boolean'; +}; + +/** + * Returns true if object is array, otherwise false + * + * @method isArray + * @param {Object} + * @return {Boolean} + */ +var isArray = function (object) { + return object instanceof Array; +}; + +/** + * Returns true if given string is valid json object + * + * @method isJson + * @param {String} + * @return {Boolean} + */ +var isJson = function (str) { + try { + return !!JSON.parse(str); + } catch (e) { + return false; + } +}; + +/** + * This method should be called to check if string is valid ethereum IBAN number + * Supports direct and indirect IBANs + * + * @method isIBAN + * @param {String} + * @return {Boolean} + */ +var isIBAN = function (iban) { + return /^XE[0-9]{2}(ETH[0-9A-Z]{13}|[0-9A-Z]{30})$/.test(iban); +}; + +module.exports = { + padLeft: padLeft, + toHex: toHex, + toDecimal: toDecimal, + fromDecimal: fromDecimal, + toAscii: toAscii, + fromAscii: fromAscii, + transformToFullName: transformToFullName, + extractDisplayName: extractDisplayName, + extractTypeName: extractTypeName, + toWei: toWei, + fromWei: fromWei, + toBigNumber: toBigNumber, + toTwosComplement: toTwosComplement, + toAddress: toAddress, + isBigNumber: isBigNumber, + isStrictAddress: isStrictAddress, + isAddress: isAddress, + isFunction: isFunction, + isString: isString, + isObject: isObject, + isBoolean: isBoolean, + isArray: isArray, + isJson: isJson, + isIBAN: isIBAN +}; + + +},{"bignumber.js":"bignumber.js"}],8:[function(require,module,exports){ +module.exports={ + "version": "0.6.0" +} + +},{}],9:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file web3.js + * @authors: + * Jeffrey Wilcke + * Marek Kotewicz + * Marian Oancea + * Fabian Vogelsteller + * Gav Wood + * @date 2014 + */ + +var version = require('./version.json'); +var net = require('./web3/net'); +var eth = require('./web3/eth'); +var db = require('./web3/db'); +var shh = require('./web3/shh'); +var watches = require('./web3/watches'); +var Filter = require('./web3/filter'); +var utils = require('./utils/utils'); +var formatters = require('./web3/formatters'); +var RequestManager = require('./web3/requestmanager'); +var c = require('./utils/config'); +var Property = require('./web3/property'); +var Batch = require('./web3/batch'); +var sha3 = require('./utils/sha3'); + +var web3Properties = [ + new Property({ + name: 'version.client', + getter: 'web3_clientVersion' + }), + new Property({ + name: 'version.network', + getter: 'net_version', + inputFormatter: utils.toDecimal + }), + new Property({ + name: 'version.ethereum', + getter: 'eth_protocolVersion', + inputFormatter: utils.toDecimal + }), + new Property({ + name: 'version.whisper', + getter: 'shh_version', + inputFormatter: utils.toDecimal + }) +]; + +/// creates methods in a given object based on method description on input +/// setups api calls for these methods +var setupMethods = function (obj, methods) { + methods.forEach(function (method) { + method.attachToObject(obj); + }); +}; + +/// creates properties in a given object based on properties description on input +/// setups api calls for these properties +var setupProperties = function (obj, properties) { + properties.forEach(function (property) { + property.attachToObject(obj); + }); +}; + +/// setups web3 object, and it's in-browser executed methods +var web3 = {}; +web3.providers = {}; +web3.version = {}; +web3.version.api = version.version; +web3.eth = {}; + +/*jshint maxparams:4 */ +web3.eth.filter = function (fil, eventParams, options, formatter) { + + // if its event, treat it differently + // TODO: simplify and remove + if (fil._isEvent) { + return fil(eventParams, options); + } + + // output logs works for blockFilter and pendingTransaction filters? + return new Filter(fil, watches.eth(), formatter || formatters.outputLogFormatter); +}; +/*jshint maxparams:3 */ + +web3.shh = {}; +web3.shh.filter = function (fil) { + return new Filter(fil, watches.shh(), formatters.outputPostFormatter); +}; +web3.net = {}; +web3.db = {}; +web3.setProvider = function (provider) { + RequestManager.getInstance().setProvider(provider); +}; +web3.reset = function () { + RequestManager.getInstance().reset(); + c.defaultBlock = 'latest'; + c.defaultAccount = undefined; +}; +web3.toHex = utils.toHex; +web3.toAscii = utils.toAscii; +web3.fromAscii = utils.fromAscii; +web3.toDecimal = utils.toDecimal; +web3.fromDecimal = utils.fromDecimal; +web3.toBigNumber = utils.toBigNumber; +web3.toWei = utils.toWei; +web3.fromWei = utils.fromWei; +web3.isAddress = utils.isAddress; +web3.isIBAN = utils.isIBAN; +web3.sha3 = sha3; +web3.createBatch = function () { + return new Batch(); +}; + +// ADD defaultblock +Object.defineProperty(web3.eth, 'defaultBlock', { + get: function () { + return c.defaultBlock; + }, + set: function (val) { + c.defaultBlock = val; + return val; + } +}); + +Object.defineProperty(web3.eth, 'defaultAccount', { + get: function () { + return c.defaultAccount; + }, + set: function (val) { + c.defaultAccount = val; + return val; + } +}); + + +// EXTEND +web3._extend = function(extension){ + /*jshint maxcomplexity: 6 */ + + if(extension.property && !web3[extension.property]) + web3[extension.property] = {}; + + setupMethods(web3[extension.property] || web3, extension.methods || []); + setupProperties(web3[extension.property] || web3, extension.properties || []); +}; +web3._extend.formatters = formatters; +web3._extend.utils = utils; +web3._extend.Method = require('./web3/method'); +web3._extend.Property = require('./web3/property'); + + +/// setups all api methods +setupProperties(web3, web3Properties); +setupMethods(web3.net, net.methods); +setupProperties(web3.net, net.properties); +setupMethods(web3.eth, eth.methods); +setupProperties(web3.eth, eth.properties); +setupMethods(web3.db, db.methods); +setupMethods(web3.shh, shh.methods); + +module.exports = web3; + + +},{"./utils/config":5,"./utils/sha3":6,"./utils/utils":7,"./version.json":8,"./web3/batch":10,"./web3/db":12,"./web3/eth":14,"./web3/filter":16,"./web3/formatters":17,"./web3/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. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** + * @file batch.js + * @author Marek Kotewicz + * @date 2015 + */ + +var RequestManager = require('./requestmanager'); + +var Batch = function () { + this.requests = []; +}; + +/** + * Should be called to add create new request to batch request + * + * @method add + * @param {Object} jsonrpc requet object + */ +Batch.prototype.add = function (request) { + this.requests.push(request); +}; + +/** + * Should be called to execute batch request + * + * @method execute + */ +Batch.prototype.execute = function () { + var requests = this.requests; + RequestManager.getInstance().sendBatch(requests, function (err, results) { + results = results || []; + requests.map(function (request, index) { + return results[index] || {}; + }).map(function (result, index) { + return requests[index].format ? requests[index].format(result.result) : result.result; + }).forEach(function (result, index) { + if (requests[index].callback) { + requests[index].callback(err, result); + } + }); + }); +}; + +module.exports = Batch; + + +},{"./requestmanager":27}],11:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** + * @file contract.js + * @author Marek Kotewicz + * @date 2014 + */ + +var web3 = require('../web3'); +var utils = require('../utils/utils'); +var coder = require('../solidity/coder'); +var SolidityEvent = require('./event'); +var SolidityFunction = require('./function'); + +/** + * Should be called to encode constructor params + * + * @method encodeConstructorParams + * @param {Array} abi + * @param {Array} constructor params + */ +var encodeConstructorParams = function (abi, params) { + return abi.filter(function (json) { + return json.type === 'constructor' && json.inputs.length === params.length; + }).map(function (json) { + return json.inputs.map(function (input) { + return input.type; + }); + }).map(function (types) { + return coder.encodeParams(types, params); + })[0] || ''; +}; + +/** + * Should be called to add functions to contract object + * + * @method addFunctionsToContract + * @param {Contract} contract + * @param {Array} abi + */ +var addFunctionsToContract = function (contract, abi) { + abi.filter(function (json) { + return json.type === 'function'; + }).map(function (json) { + return new SolidityFunction(json, contract.address); + }).forEach(function (f) { + f.attachToContract(contract); + }); +}; + +/** + * Should be called to add events to contract object + * + * @method addEventsToContract + * @param {Contract} contract + * @param {Array} abi + */ +var addEventsToContract = function (contract, abi) { + abi.filter(function (json) { + return json.type === 'event'; + }).map(function (json) { + return new SolidityEvent(json, contract.address); + }).forEach(function (e) { + e.attachToContract(contract); + }); +}; + +/** + * Should be called to create new ContractFactory + * + * @method contract + * @param {Array} abi + * @returns {ContractFactory} new contract factory + */ +var contract = function (abi) { + return new ContractFactory(abi); +}; + +/** + * Should be called to create new ContractFactory instance + * + * @method ContractFactory + * @param {Array} abi + */ +var ContractFactory = function (abi) { + this.abi = abi; +}; + +/** + * Should be called to create new contract on a blockchain + * + * @method new + * @param {Any} contract constructor param1 (optional) + * @param {Any} contract constructor param2 (optional) + * @param {Object} contract transaction object (required) + * @param {Function} callback + * @returns {Contract} returns contract if no callback was passed, + * otherwise calls callback function (err, contract) + */ +ContractFactory.prototype.new = function () { + // parse arguments + var options = {}; // required! + var callback; + + var args = Array.prototype.slice.call(arguments); + if (utils.isFunction(args[args.length - 1])) { + callback = args.pop(); + } + + var last = args[args.length - 1]; + if (utils.isObject(last) && !utils.isArray(last)) { + options = args.pop(); + } + + // throw an error if there are no options + + var bytes = encodeConstructorParams(this.abi, args); + options.data += bytes; + + if (!callback) { + var address = web3.eth.sendTransaction(options); + return this.at(address); + } + + var self = this; + web3.eth.sendTransaction(options, function (err, address) { + if (err) { + callback(err); + } + self.at(address, callback); + }); +}; + +/** + * Should be called to get access to existing contract on a blockchain + * + * @method at + * @param {Address} contract address (required) + * @param {Function} callback {optional) + * @returns {Contract} returns contract if no callback was passed, + * otherwise calls callback function (err, contract) + */ +ContractFactory.prototype.at = function (address, callback) { + // TODO: address is required + + if (callback) { + callback(null, new Contract(this.abi, address)); + } + return new Contract(this.abi, address); +}; + +/** + * Should be called to create new contract instance + * + * @method Contract + * @param {Array} abi + * @param {Address} contract address + */ +var Contract = function (abi, address) { + this.address = address; + addFunctionsToContract(this, abi); + addEventsToContract(this, abi); +}; + +module.exports = contract; + + +},{"../solidity/coder":1,"../utils/utils":7,"../web3":9,"./event":15,"./function":18}],12:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file db.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +var Method = require('./method'); + +var putString = new Method({ + name: 'putString', + call: 'db_putString', + params: 3 +}); + + +var getString = new Method({ + name: 'getString', + call: 'db_getString', + params: 2 +}); + +var putHex = new Method({ + name: 'putHex', + call: 'db_putHex', + params: 3 +}); + +var getHex = new Method({ + name: 'getHex', + call: 'db_getHex', + params: 2 +}); + +var methods = [ + putString, getString, putHex, getHex +]; + +module.exports = { + methods: methods +}; + +},{"./method":22}],13:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** + * @file errors.js + * @author Marek Kotewicz + * @date 2015 + */ + +module.exports = { + InvalidNumberOfParams: function () { + return new Error('Invalid number of input parameters'); + }, + InvalidConnection: function (host){ + return new Error('CONNECTION ERROR: Couldn\'t connect to node '+ host +', is it running?'); + }, + InvalidProvider: function () { + return new Error('Providor not set or invalid'); + }, + InvalidResponse: function (result){ + var message = !!result && !!result.error && !!result.error.message ? result.error.message : 'Invalid JSON RPC response'; + return new Error(message); + } +}; + + +},{}],14:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** + * @file eth.js + * @author Marek Kotewicz + * @author Fabian Vogelsteller + * @date 2015 + */ + +/** + * Web3 + * + * @module web3 + */ + +/** + * Eth methods and properties + * + * An example method object can look as follows: + * + * { + * name: 'getBlock', + * call: blockCall, + * params: 2, + * outputFormatter: formatters.outputBlockFormatter, + * inputFormatter: [ // can be a formatter funciton or an array of functions. Where each item in the array will be used for one parameter + * utils.toHex, // formats paramter 1 + * function(param){ return !!param; } // formats paramter 2 + * ] + * }, + * + * @class [web3] eth + * @constructor + */ + +"use strict"; + +var formatters = require('./formatters'); +var utils = require('../utils/utils'); +var Method = require('./method'); +var Property = require('./property'); + +var blockCall = function (args) { + return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? "eth_getBlockByHash" : "eth_getBlockByNumber"; +}; + +var transactionFromBlockCall = function (args) { + return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getTransactionByBlockHashAndIndex' : 'eth_getTransactionByBlockNumberAndIndex'; +}; + +var uncleCall = function (args) { + return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleByBlockHashAndIndex' : 'eth_getUncleByBlockNumberAndIndex'; +}; + +var getBlockTransactionCountCall = function (args) { + return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getBlockTransactionCountByHash' : 'eth_getBlockTransactionCountByNumber'; +}; + +var uncleCountCall = function (args) { + return (utils.isString(args[0]) && args[0].indexOf('0x') === 0) ? 'eth_getUncleCountByBlockHash' : 'eth_getUncleCountByBlockNumber'; +}; + +/// @returns an array of objects describing web3.eth api methods + +var getBalance = new Method({ + name: 'getBalance', + call: 'eth_getBalance', + params: 2, + inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter], + outputFormatter: formatters.outputBigNumberFormatter +}); + +var getStorageAt = new Method({ + name: 'getStorageAt', + call: 'eth_getStorageAt', + params: 3, + inputFormatter: [null, utils.toHex, formatters.inputDefaultBlockNumberFormatter] +}); + +var getCode = new Method({ + name: 'getCode', + call: 'eth_getCode', + params: 2, + inputFormatter: [utils.toAddress, formatters.inputDefaultBlockNumberFormatter] +}); + +var getBlock = new Method({ + name: 'getBlock', + call: blockCall, + params: 2, + inputFormatter: [formatters.inputBlockNumberFormatter, function (val) { return !!val; }], + outputFormatter: formatters.outputBlockFormatter +}); + +var getUncle = new Method({ + name: 'getUncle', + call: uncleCall, + params: 2, + inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex], + outputFormatter: formatters.outputBlockFormatter, + +}); + +var getCompilers = new Method({ + name: 'getCompilers', + call: 'eth_getCompilers', + params: 0 +}); + +var getBlockTransactionCount = new Method({ + name: 'getBlockTransactionCount', + call: getBlockTransactionCountCall, + params: 1, + inputFormatter: [formatters.inputBlockNumberFormatter], + outputFormatter: utils.toDecimal +}); + +var getBlockUncleCount = new Method({ + name: 'getBlockUncleCount', + call: uncleCountCall, + params: 1, + inputFormatter: [formatters.inputBlockNumberFormatter], + outputFormatter: utils.toDecimal +}); + +var getTransaction = new Method({ + name: 'getTransaction', + call: 'eth_getTransactionByHash', + params: 1, + outputFormatter: formatters.outputTransactionFormatter +}); + +var getTransactionFromBlock = new Method({ + name: 'getTransactionFromBlock', + call: transactionFromBlockCall, + params: 2, + inputFormatter: [formatters.inputBlockNumberFormatter, utils.toHex], + outputFormatter: formatters.outputTransactionFormatter +}); + +var getTransactionCount = new Method({ + name: 'getTransactionCount', + call: 'eth_getTransactionCount', + params: 2, + inputFormatter: [null, formatters.inputDefaultBlockNumberFormatter], + outputFormatter: utils.toDecimal +}); + +var sendRawTransaction = new Method({ + name: 'sendRawTransaction', + call: 'eth_sendRawTransaction', + params: 1, + inputFormatter: [] +}); + +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, + sendRawTransaction, + sendTransaction, + compileSolidity, + compileLLL, + compileSerpent, + submitWork, + getWork +]; + +/// @returns an array of objects describing web3.eth api properties + + + +var properties = [ + new Property({ + name: 'coinbase', + getter: 'eth_coinbase' + }), + new Property({ + name: 'mining', + getter: 'eth_mining' + }), + new Property({ + name: 'hashrate', + getter: 'eth_hashrate', + outputFormatter: utils.toDecimal + }), + new Property({ + name: 'gasPrice', + getter: 'eth_gasPrice', + outputFormatter: formatters.outputBigNumberFormatter + }), + new Property({ + name: 'accounts', + getter: 'eth_accounts' + }), + new Property({ + name: 'blockNumber', + getter: 'eth_blockNumber', + outputFormatter: utils.toDecimal + }) +]; + +module.exports = { + methods: methods, + properties: properties +}; + + +},{"../utils/utils":7,"./formatters":17,"./method":22,"./property":25}],15:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** + * @file event.js + * @author Marek Kotewicz + * @date 2014 + */ + +var utils = require('../utils/utils'); +var coder = require('../solidity/coder'); +var web3 = require('../web3'); +var formatters = require('./formatters'); +var sha3 = require('../utils/sha3'); + +/** + * This prototype should be used to create event filters + */ +var SolidityEvent = function (json, address) { + this._params = json.inputs; + this._name = utils.transformToFullName(json); + this._address = address; + this._anonymous = json.anonymous; +}; + +/** + * Should be used to get filtered param types + * + * @method types + * @param {Bool} decide if returned typed should be indexed + * @return {Array} array of types + */ +SolidityEvent.prototype.types = function (indexed) { + return this._params.filter(function (i) { + return i.indexed === indexed; + }).map(function (i) { + return i.type; + }); +}; + +/** + * Should be used to get event display name + * + * @method displayName + * @return {String} event display name + */ +SolidityEvent.prototype.displayName = function () { + return utils.extractDisplayName(this._name); +}; + +/** + * Should be used to get event type name + * + * @method typeName + * @return {String} event type name + */ +SolidityEvent.prototype.typeName = function () { + return utils.extractTypeName(this._name); +}; + +/** + * Should be used to get event signature + * + * @method signature + * @return {String} event signature + */ +SolidityEvent.prototype.signature = function () { + return sha3(this._name); +}; + +/** + * Should be used to encode indexed params and options to one final object + * + * @method encode + * @param {Object} indexed + * @param {Object} options + * @return {Object} everything combined together and encoded + */ +SolidityEvent.prototype.encode = function (indexed, options) { + indexed = indexed || {}; + options = options || {}; + var result = {}; + + ['fromBlock', 'toBlock'].filter(function (f) { + return options[f] !== undefined; + }).forEach(function (f) { + result[f] = formatters.inputBlockNumberFormatter(options[f]); + }); + + result.topics = []; + + if (!this._anonymous) { + result.address = this._address; + result.topics.push('0x' + this.signature()); + } + + var indexedTopics = this._params.filter(function (i) { + return i.indexed === true; + }).map(function (i) { + var value = indexed[i.name]; + if (value === undefined || value === null) { + return null; + } + + if (utils.isArray(value)) { + return value.map(function (v) { + return '0x' + coder.encodeParam(i.type, v); + }); + } + return '0x' + coder.encodeParam(i.type, value); + }); + + result.topics = result.topics.concat(indexedTopics); + + return result; +}; + +/** + * Should be used to decode indexed params and options + * + * @method decode + * @param {Object} data + * @return {Object} result object with decoded indexed && not indexed params + */ +SolidityEvent.prototype.decode = function (data) { + + data.data = data.data || ''; + data.topics = data.topics || []; + + var argTopics = this._anonymous ? data.topics : data.topics.slice(1); + var indexedData = argTopics.map(function (topics) { return topics.slice(2); }).join(""); + var indexedParams = coder.decodeParams(this.types(true), indexedData); + + var notIndexedData = data.data.slice(2); + var notIndexedParams = coder.decodeParams(this.types(false), notIndexedData); + + var result = formatters.outputLogFormatter(data); + result.event = this.displayName(); + result.address = data.address; + + result.args = this._params.reduce(function (acc, current) { + acc[current.name] = current.indexed ? indexedParams.shift() : notIndexedParams.shift(); + return acc; + }, {}); + + delete result.data; + delete result.topics; + + return result; +}; + +/** + * Should be used to create new filter object from event + * + * @method execute + * @param {Object} indexed + * @param {Object} options + * @return {Object} filter object + */ +SolidityEvent.prototype.execute = function (indexed, options) { + var o = this.encode(indexed, options); + var formatter = this.decode.bind(this); + return web3.eth.filter(o, undefined, undefined, formatter); +}; + +/** + * Should be used to attach event to contract object + * + * @method attachToContract + * @param {Contract} + */ +SolidityEvent.prototype.attachToContract = function (contract) { + var execute = this.execute.bind(this); + var displayName = this.displayName(); + if (!contract[displayName]) { + contract[displayName] = execute; + } + contract[displayName][this.typeName()] = this.execute.bind(this, contract); +}; + +module.exports = SolidityEvent; + + +},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9,"./formatters":17}],16:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file filter.js + * @authors: + * Jeffrey Wilcke + * Marek Kotewicz + * Marian Oancea + * Fabian Vogelsteller + * Gav Wood + * @date 2014 + */ + +var RequestManager = require('./requestmanager'); +var formatters = require('./formatters'); +var utils = require('../utils/utils'); + +/** +* Converts a given topic to a hex string, but also allows null values. +* +* @param {Mixed} value +* @return {String} +*/ +var toTopic = function(value){ + + if(value === null || typeof value === 'undefined') + return null; + + value = String(value); + + if(value.indexOf('0x') === 0) + return value; + else + return utils.fromAscii(value); +}; + +/// This method should be called on options object, to verify deprecated properties && lazy load dynamic ones +/// @param should be string or object +/// @returns options string or object +var getOptions = function (options) { + + if (utils.isString(options)) { + return options; + } + + options = options || {}; + + // make sure topics, get converted to hex + options.topics = options.topics || []; + options.topics = options.topics.map(function(topic){ + return (utils.isArray(topic)) ? topic.map(toTopic) : toTopic(topic); + }); + + // lazy load + return { + topics: options.topics, + to: options.to, + address: options.address, + fromBlock: formatters.inputBlockNumberFormatter(options.fromBlock), + toBlock: formatters.inputBlockNumberFormatter(options.toBlock) + }; +}; + +/** +Adds the callback and sets up the methods, to iterate over the results. + +@method getLogsAtStart +@param {Object} self +@param {funciton} +*/ +var getLogsAtStart = function(self, callback){ + // call getFilterLogs for the first watch callback start + if (!utils.isString(self.options)) { + self.get(function (err, messages) { + // don't send all the responses to all the watches again... just to self one + if (err) { + callback(err); + } + + messages.forEach(function (message) { + callback(null, message); + }); + }); + } +}; + +/** +Adds the callback and sets up the methods, to iterate over the results. + +@method pollFilter +@param {Object} self +*/ +var pollFilter = function(self) { + + 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); + }); + }); + }; + + RequestManager.getInstance().startPolling({ + method: self.implementation.poll.call, + params: [self.filterId], + }, self.filterId, onMessage, self.stopWatching.bind(self)); + +}; + +var Filter = function (options, methods, formatter) { + var self = this; + var implementation = {}; + methods.forEach(function (method) { + method.attachToObject(implementation); + }); + this.options = getOptions(options); + this.implementation = implementation; + this.callbacks = []; + this.pollFilters = []; + this.formatter = formatter; + this.implementation.newFilter(this.options, function(error, id){ + if(error) { + self.callbacks.forEach(function(callback){ + callback(error); + }); + } else { + self.filterId = id; + // get filter logs at start + self.callbacks.forEach(function(callback){ + getLogsAtStart(self, callback); + }); + pollFilter(self); + } + }); +}; + +Filter.prototype.watch = function (callback) { + this.callbacks.push(callback); + + if(this.filterId) { + getLogsAtStart(this, callback); + pollFilter(this); + } + + return this; +}; + +Filter.prototype.stopWatching = function () { + RequestManager.getInstance().stopPolling(this.filterId); + // remove filter async + this.implementation.uninstallFilter(this.filterId, function(){}); + 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; + }); + } + + return this; +}; + +module.exports = Filter; + + +},{"../utils/utils":7,"./formatters":17,"./requestmanager":27}],17:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** + * @file formatters.js + * @author Marek Kotewicz + * @author Fabian Vogelsteller + * @date 2015 + */ + +var utils = require('../utils/utils'); +var config = require('../utils/config'); + +/** + * Should the format output to a big number + * + * @method outputBigNumberFormatter + * @param {String|Number|BigNumber} + * @returns {BigNumber} object + */ +var outputBigNumberFormatter = function (number) { + return utils.toBigNumber(number); +}; + +var isPredefinedBlockNumber = function (blockNumber) { + return blockNumber === 'latest' || blockNumber === 'pending' || blockNumber === 'earliest'; +}; + +var inputDefaultBlockNumberFormatter = function (blockNumber) { + if (blockNumber === undefined) { + return config.defaultBlock; + } + return inputBlockNumberFormatter(blockNumber); +}; + +var inputBlockNumberFormatter = function (blockNumber) { + if (blockNumber === undefined) { + return undefined; + } else if (isPredefinedBlockNumber(blockNumber)) { + return blockNumber; + } + return utils.toHex(blockNumber); +}; + +/** + * Formats the input of a transaction and converts all values to HEX + * + * @method inputTransactionFormatter + * @param {Object} transaction options + * @returns object +*/ +var inputTransactionFormatter = function (options){ + + options.from = options.from || config.defaultAccount; + + // make code -> data + if (options.code) { + options.data = options.code; + delete options.code; + } + + ['gasPrice', 'gas', 'value', 'nonce'].filter(function (key) { + return options[key] !== undefined; + }).forEach(function(key){ + options[key] = utils.fromDecimal(options[key]); + }); + + return options; +}; + +/** + * Formats the output of a transaction to its proper values + * + * @method outputTransactionFormatter + * @param {Object} transaction + * @returns {Object} transaction +*/ +var outputTransactionFormatter = function (tx){ + if(tx.blockNumber !== null) + tx.blockNumber = utils.toDecimal(tx.blockNumber); + if(tx.transactionIndex !== null) + 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); + if(block.number !== null) + 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.blockNumber !== null) + log.blockNumber = utils.toDecimal(log.blockNumber); + if(log.transactionIndex !== null) + log.transactionIndex = utils.toDecimal(log.transactionIndex); + if(log.logIndex !== null) + log.logIndex = utils.toDecimal(log.logIndex); + + return log; +}; + +/** + * Formats the input of a whisper post and converts all values to HEX + * + * @method inputPostFormatter + * @param {Object} transaction object + * @returns {Object} +*/ +var inputPostFormatter = function(post) { + + post.payload = utils.toHex(post.payload); + post.ttl = utils.fromDecimal(post.ttl); + post.workToProve = utils.fromDecimal(post.workToProve); + post.priority = utils.fromDecimal(post.priority); + + // fallback + if (!utils.isArray(post.topics)) { + post.topics = post.topics ? [post.topics] : []; + } + + // format the following options + post.topics = post.topics.map(function(topic){ + return utils.fromAscii(topic); + }); + + return post; +}; + +/** + * Formats the output of a received post message + * + * @method outputPostFormatter + * @param {Object} + * @returns {Object} + */ +var outputPostFormatter = function(post){ + + post.expiry = utils.toDecimal(post.expiry); + post.sent = utils.toDecimal(post.sent); + post.ttl = utils.toDecimal(post.ttl); + post.workProved = utils.toDecimal(post.workProved); + post.payloadRaw = post.payload; + post.payload = utils.toAscii(post.payload); + + if (utils.isJson(post.payload)) { + post.payload = JSON.parse(post.payload); + } + + // format the following options + if (!post.topics) { + post.topics = []; + } + post.topics = post.topics.map(function(topic){ + return utils.toAscii(topic); + }); + + return post; +}; + +module.exports = { + inputDefaultBlockNumberFormatter: inputDefaultBlockNumberFormatter, + inputBlockNumberFormatter: inputBlockNumberFormatter, + inputTransactionFormatter: inputTransactionFormatter, + inputPostFormatter: inputPostFormatter, + outputBigNumberFormatter: outputBigNumberFormatter, + outputTransactionFormatter: outputTransactionFormatter, + outputBlockFormatter: outputBlockFormatter, + outputLogFormatter: outputLogFormatter, + outputPostFormatter: outputPostFormatter +}; + + +},{"../utils/config":5,"../utils/utils":7}],18:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** + * @file function.js + * @author Marek Kotewicz + * @date 2015 + */ + +var web3 = require('../web3'); +var coder = require('../solidity/coder'); +var utils = require('../utils/utils'); +var formatters = require('./formatters'); +var sha3 = require('../utils/sha3'); + +/** + * This prototype should be used to call/sendTransaction to solidity functions + */ +var SolidityFunction = function (json, address) { + this._inputTypes = json.inputs.map(function (i) { + return i.type; + }); + this._outputTypes = json.outputs.map(function (i) { + return i.type; + }); + this._constant = json.constant; + this._name = utils.transformToFullName(json); + this._address = address; +}; + +SolidityFunction.prototype.extractCallback = function (args) { + if (utils.isFunction(args[args.length - 1])) { + return args.pop(); // modify the args array! + } +}; + +SolidityFunction.prototype.extractDefaultBlock = function (args) { + if (args.length > this._inputTypes.length && !utils.isObject(args[args.length -1])) { + return formatters.inputDefaultBlockNumberFormatter(args.pop()); // modify the args array! + } +}; + +/** + * Should be used to create payload from arguments + * + * @method toPayload + * @param {Array} solidity function params + * @param {Object} optional payload options + */ +SolidityFunction.prototype.toPayload = function (args) { + var options = {}; + if (args.length > this._inputTypes.length && utils.isObject(args[args.length -1])) { + options = args[args.length - 1]; + } + options.to = this._address; + options.data = '0x' + this.signature() + coder.encodeParams(this._inputTypes, args); + return options; +}; + +/** + * Should be used to get function signature + * + * @method signature + * @return {String} function signature + */ +SolidityFunction.prototype.signature = function () { + return sha3(this._name).slice(0, 8); +}; + + +SolidityFunction.prototype.unpackOutput = function (output) { + if (!output) { + return; + } + + output = output.length >= 2 ? output.slice(2) : output; + var result = coder.decodeParams(this._outputTypes, output); + return result.length === 1 ? result[0] : result; +}; + +/** + * Calls a contract function. + * + * @method call + * @param {...Object} Contract function arguments + * @param {function} If the last argument is a function, the contract function + * call will be asynchronous, and the callback will be passed the + * error and result. + * @return {String} output bytes + */ +SolidityFunction.prototype.call = function () { + var args = Array.prototype.slice.call(arguments).filter(function (a) {return a !== undefined; }); + var callback = this.extractCallback(args); + var defaultBlock = this.extractDefaultBlock(args); + var payload = this.toPayload(args); + + + if (!callback) { + var output = web3.eth.call(payload, defaultBlock); + return this.unpackOutput(output); + } + + var self = this; + web3.eth.call(payload, defaultBlock, function (error, output) { + callback(error, self.unpackOutput(output)); + }); +}; + +/** + * Should be used to sendTransaction to solidity function + * + * @method sendTransaction + * @param {Object} options + */ +SolidityFunction.prototype.sendTransaction = function () { + var args = Array.prototype.slice.call(arguments).filter(function (a) {return a !== undefined; }); + var callback = this.extractCallback(args); + var payload = this.toPayload(args); + + if (!callback) { + return web3.eth.sendTransaction(payload); + } + + web3.eth.sendTransaction(payload, callback); +}; + +/** + * Should be used to estimateGas of solidity function + * + * @method estimateGas + * @param {Object} options + */ +SolidityFunction.prototype.estimateGas = function () { + var args = Array.prototype.slice.call(arguments); + var callback = this.extractCallback(args); + var payload = this.toPayload(args); + + if (!callback) { + return web3.eth.estimateGas(payload); + } + + web3.eth.estimateGas(payload, callback); +}; + +/** + * Should be used to get function display name + * + * @method displayName + * @return {String} display name of the function + */ +SolidityFunction.prototype.displayName = function () { + return utils.extractDisplayName(this._name); +}; + +/** + * Should be used to get function type name + * + * @method typeName + * @return {String} type name of the function + */ +SolidityFunction.prototype.typeName = function () { + return utils.extractTypeName(this._name); +}; + +/** + * Should be called to get rpc requests from solidity function + * + * @method request + * @returns {Object} + */ +SolidityFunction.prototype.request = function () { + var args = Array.prototype.slice.call(arguments); + var callback = this.extractCallback(args); + var payload = this.toPayload(args); + var format = this.unpackOutput.bind(this); + + return { + callback: callback, + payload: payload, + format: format + }; +}; + +/** + * Should be called to execute function + * + * @method execute + */ +SolidityFunction.prototype.execute = function () { + var transaction = !this._constant; + + // send transaction + if (transaction) { + return this.sendTransaction.apply(this, Array.prototype.slice.call(arguments)); + } + + // call + return this.call.apply(this, Array.prototype.slice.call(arguments)); +}; + +/** + * Should be called to attach function to contract + * + * @method attachToContract + * @param {Contract} + */ +SolidityFunction.prototype.attachToContract = function (contract) { + var execute = this.execute.bind(this); + execute.request = this.request.bind(this); + execute.call = this.call.bind(this); + execute.sendTransaction = this.sendTransaction.bind(this); + execute.estimateGas = this.estimateGas.bind(this); + var displayName = this.displayName(); + if (!contract[displayName]) { + contract[displayName] = execute; + } + contract[displayName][this.typeName()] = execute; // circular!!!! +}; + +module.exports = SolidityFunction; + + +},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9,"./formatters":17}],19:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file httpprovider.js + * @authors: + * Marek Kotewicz + * Marian Oancea + * Fabian Vogelsteller + * @date 2014 + */ + +"use strict"; + +var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // jshint ignore:line +var errors = require('./errors'); + +var HttpProvider = function (host) { + this.host = host || 'http://localhost:8545'; +}; + +HttpProvider.prototype.send = function (payload) { + var request = new XMLHttpRequest(); + + request.open('POST', this.host, false); + request.setRequestHeader('Content-type','application/json'); + + 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); + request.setRequestHeader('Content-type','application/json'); + + try { + request.send(JSON.stringify(payload)); + } catch(error) { + callback(errors.InvalidConnection(this.host)); + } +}; + +module.exports = HttpProvider; + + +},{"./errors":13,"xmlhttprequest":4}],20:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** + * @file icap.js + * @author Marek Kotewicz + * @date 2015 + */ + +var utils = require('../utils/utils'); + +/** + * This prototype should be used to extract necessary information from iban address + * + * @param {String} iban + */ +var ICAP = function (iban) { + this._iban = iban; +}; + +/** + * Should be called to check if icap is correct + * + * @method isValid + * @returns {Boolean} true if it is, otherwise false + */ +ICAP.prototype.isValid = function () { + return utils.isIBAN(this._iban); +}; + +/** + * Should be called to check if iban number is direct + * + * @method isDirect + * @returns {Boolean} true if it is, otherwise false + */ +ICAP.prototype.isDirect = function () { + return this._iban.length === 34; +}; + +/** + * Should be called to check if iban number if indirect + * + * @method isIndirect + * @returns {Boolean} true if it is, otherwise false + */ +ICAP.prototype.isIndirect = function () { + return this._iban.length === 20; +}; + +/** + * Should be called to get iban checksum + * Uses the mod-97-10 checksumming protocol (ISO/IEC 7064:2003) + * + * @method checksum + * @returns {String} checksum + */ +ICAP.prototype.checksum = function () { + return this._iban.substr(2, 2); +}; + +/** + * Should be called to get institution identifier + * eg. XREG + * + * @method institution + * @returns {String} institution identifier + */ +ICAP.prototype.institution = function () { + return this.isIndirect() ? this._iban.substr(7, 4) : ''; +}; + +/** + * Should be called to get client identifier within institution + * eg. GAVOFYORK + * + * @method client + * @returns {String} client identifier + */ +ICAP.prototype.client = function () { + return this.isIndirect() ? this._iban.substr(11) : ''; +}; + +/** + * Should be called to get client direct address + * + * @method address + * @returns {String} client direct address + */ +ICAP.prototype.address = function () { + return this.isDirect() ? this._iban.substr(4) : ''; +}; + +module.exports = ICAP; + + +},{"../utils/utils":7}],21:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file jsonrpc.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +var Jsonrpc = function () { + // singleton pattern + if (arguments.callee._singletonInstance) { + return arguments.callee._singletonInstance; + } + arguments.callee._singletonInstance = this; + + this.messageId = 1; +}; + +/** + * @return {Jsonrpc} singleton + */ +Jsonrpc.getInstance = function () { + var instance = new Jsonrpc(); + return instance; +}; + +/** + * Should be called to valid json create payload object + * + * @method toPayload + * @param {Function} method of jsonrpc call, required + * @param {Array} params, an array of method params, optional + * @returns {Object} valid jsonrpc payload object + */ +Jsonrpc.prototype.toPayload = function (method, params) { + if (!method) + console.error('jsonrpc method should be specified!'); + + return { + jsonrpc: '2.0', + method: method, + params: params || [], + id: this.messageId++ + }; +}; + +/** + * Should be called to check if jsonrpc response is valid + * + * @method isValidResponse + * @param {Object} + * @returns {Boolean} true if response is valid, otherwise false + */ +Jsonrpc.prototype.isValidResponse = function (response) { + return !!response && + !response.error && + response.jsonrpc === '2.0' && + typeof response.id === 'number' && + response.result !== undefined; // only undefined is not valid json object +}; + +/** + * Should be called to create batch payload object + * + * @method toBatchPayload + * @param {Array} messages, an array of objects with method (required) and params (optional) fields + * @returns {Array} batch payload + */ +Jsonrpc.prototype.toBatchPayload = function (messages) { + var self = this; + return messages.map(function (message) { + return self.toPayload(message.method, message.params); + }); +}; + +module.exports = Jsonrpc; + + +},{}],22:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** + * @file method.js + * @author Marek Kotewicz + * @date 2015 + */ + +var RequestManager = require('./requestmanager'); +var utils = require('../utils/utils'); +var errors = require('./errors'); + +var Method = function (options) { + this.name = options.name; + this.call = options.call; + this.params = options.params || 0; + this.inputFormatter = options.inputFormatter; + this.outputFormatter = options.outputFormatter; +}; + +/** + * Should be used to determine name of the jsonrpc method based on arguments + * + * @method getCall + * @param {Array} arguments + * @return {String} name of jsonrpc method + */ +Method.prototype.getCall = function (args) { + return utils.isFunction(this.call) ? this.call(args) : this.call; +}; + +/** + * Should be used to extract callback from array of arguments. Modifies input param + * + * @method extractCallback + * @param {Array} arguments + * @return {Function|Null} callback, if exists + */ +Method.prototype.extractCallback = function (args) { + if (utils.isFunction(args[args.length - 1])) { + return args.pop(); // modify the args array! + } +}; + +/** + * Should be called to check if the number of arguments is correct + * + * @method validateArgs + * @param {Array} arguments + * @throws {Error} if it is not + */ +Method.prototype.validateArgs = function (args) { + if (args.length !== this.params) { + throw errors.InvalidNumberOfParams(); + } +}; + +/** + * Should be called to format input args of method + * + * @method formatInput + * @param {Array} + * @return {Array} + */ +Method.prototype.formatInput = function (args) { + if (!this.inputFormatter) { + return args; + } + + return this.inputFormatter.map(function (formatter, index) { + return formatter ? formatter(args[index]) : args[index]; + }); +}; + +/** + * Should be called to format output(result) of method + * + * @method formatOutput + * @param {Object} + * @return {Object} + */ +Method.prototype.formatOutput = function (result) { + return this.outputFormatter && result !== null ? this.outputFormatter(result) : result; +}; + +/** + * Should attach function to method + * + * @method attachToObject + * @param {Object} + * @param {Function} + */ +Method.prototype.attachToObject = function (obj) { + var func = this.send.bind(this); + func.request = this.request.bind(this); + func.call = this.call; // that's ugly. filter.js uses it + var name = this.name.split('.'); + if (name.length > 1) { + obj[name[0]] = obj[name[0]] || {}; + obj[name[0]][name[1]] = func; + } else { + obj[name[0]] = func; + } +}; + +/** + * Should create payload from given input args + * + * @method toPayload + * @param {Array} args + * @return {Object} + */ +Method.prototype.toPayload = function (args) { + var call = this.getCall(args); + var callback = this.extractCallback(args); + var params = this.formatInput(args); + this.validateArgs(params); + + return { + method: call, + params: params, + callback: callback + }; +}; + +/** + * Should be called to create pure JSONRPC request which can be used in batch request + * + * @method request + * @param {...} params + * @return {Object} jsonrpc request + */ +Method.prototype.request = function () { + var payload = this.toPayload(Array.prototype.slice.call(arguments)); + payload.format = this.formatOutput.bind(this); + return payload; +}; + +/** + * Should send request to the API + * + * @method send + * @param list of params + * @return result + */ +Method.prototype.send = function () { + var payload = this.toPayload(Array.prototype.slice.call(arguments)); + if (payload.callback) { + var self = this; + return RequestManager.getInstance().sendAsync(payload, function (err, result) { + payload.callback(err, self.formatOutput(result)); + }); + } + return this.formatOutput(RequestManager.getInstance().send(payload)); +}; + +module.exports = Method; + + +},{"../utils/utils":7,"./errors":13,"./requestmanager":27}],23:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** + * @file namereg.js + * @author Marek Kotewicz + * @date 2015 + */ + +var contract = require('./contract'); + +var address = '0xc6d9d2cd449a754c494264e1809c50e34d64562b'; + +var abi = [ + {"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"name","outputs":[{"name":"o_name","type":"bytes32"}],"type":"function"}, + {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"}, + {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"content","outputs":[{"name":"","type":"bytes32"}],"type":"function"}, + {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"addr","outputs":[{"name":"","type":"address"}],"type":"function"}, + {"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserve","outputs":[],"type":"function"}, + {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"subRegistrar","outputs":[{"name":"o_subRegistrar","type":"address"}],"type":"function"}, + {"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_newOwner","type":"address"}],"name":"transfer","outputs":[],"type":"function"}, + {"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_registrar","type":"address"}],"name":"setSubRegistrar","outputs":[],"type":"function"}, + {"constant":false,"inputs":[],"name":"Registrar","outputs":[],"type":"function"}, + {"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_a","type":"address"},{"name":"_primary","type":"bool"}],"name":"setAddress","outputs":[],"type":"function"}, + {"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_content","type":"bytes32"}],"name":"setContent","outputs":[],"type":"function"}, + {"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"disown","outputs":[],"type":"function"}, + {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"register","outputs":[{"name":"","type":"address"}],"type":"function"}, + {"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"}],"name":"Changed","type":"event"}, + {"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"addr","type":"address"}],"name":"PrimaryChanged","type":"event"} +]; + +module.exports = contract(abi).at(address); + + +},{"./contract":11}],24:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file eth.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +var utils = require('../utils/utils'); +var Property = require('./property'); + +/// @returns an array of objects describing web3.eth api methods +var methods = [ +]; + +/// @returns an array of objects describing web3.eth api properties +var properties = [ + new Property({ + name: 'listening', + getter: 'net_listening' + }), + new Property({ + name: 'peerCount', + getter: 'net_peerCount', + outputFormatter: utils.toDecimal + }) +]; + + +module.exports = { + methods: methods, + properties: properties +}; + + +},{"../utils/utils":7,"./property":25}],25:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** + * @file property.js + * @author Fabian Vogelsteller + * @author Marek Kotewicz + * @date 2015 + */ + +var RequestManager = require('./requestmanager'); + +var Property = function (options) { + this.name = options.name; + this.getter = options.getter; + this.setter = options.setter; + this.outputFormatter = options.outputFormatter; + this.inputFormatter = options.inputFormatter; +}; + +/** + * Should be called to format input args of method + * + * @method formatInput + * @param {Array} + * @return {Array} + */ +Property.prototype.formatInput = function (arg) { + return this.inputFormatter ? this.inputFormatter(arg) : arg; +}; + +/** + * Should be called to format output(result) of method + * + * @method formatOutput + * @param {Object} + * @return {Object} + */ +Property.prototype.formatOutput = function (result) { + return this.outputFormatter && result !== null ? this.outputFormatter(result) : result; +}; + +/** + * Should attach function to method + * + * @method attachToObject + * @param {Object} + * @param {Function} + */ +Property.prototype.attachToObject = function (obj) { + var proto = { + get: this.get.bind(this), + }; + + var names = this.name.split('.'); + var name = names[0]; + if (names.length > 1) { + obj[names[0]] = obj[names[0]] || {}; + obj = obj[names[0]]; + name = names[1]; + } + + Object.defineProperty(obj, name, proto); + + var toAsyncName = function (prefix, name) { + return prefix + name.charAt(0).toUpperCase() + name.slice(1); + }; + + obj[toAsyncName('get', name)] = this.getAsync.bind(this); +}; + +/** + * Should be used to get value of the property + * + * @method get + * @return {Object} value of the property + */ +Property.prototype.get = function () { + return this.formatOutput(RequestManager.getInstance().send({ + method: this.getter + })); +}; + +/** + * Should be used to asynchrounously get value of property + * + * @method getAsync + * @param {Function} + */ +Property.prototype.getAsync = function (callback) { + var self = this; + RequestManager.getInstance().sendAsync({ + method: this.getter + }, function (err, result) { + if (err) { + return callback(err); + } + callback(err, self.formatOutput(result)); + }); +}; + +module.exports = Property; + + +},{"./requestmanager":27}],26:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file qtsync.js + * @authors: + * Marek Kotewicz + * Marian Oancea + * @date 2014 + */ + +var QtSyncProvider = function () { +}; + +QtSyncProvider.prototype.send = function (payload) { + var result = navigator.qt.callMethod(JSON.stringify(payload)); + return JSON.parse(result); +}; + +module.exports = QtSyncProvider; + + +},{}],27:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** + * @file requestmanager.js + * @author Jeffrey Wilcke + * @author Marek Kotewicz + * @author Marian Oancea + * @author Fabian Vogelsteller + * @author Gav Wood + * @date 2014 + */ + +var Jsonrpc = require('./jsonrpc'); +var utils = require('../utils/utils'); +var c = require('../utils/config'); +var errors = require('./errors'); + +/** + * It's responsible for passing messages to providers + * It's also responsible for polling the ethereum node for incoming messages + * Default poll timeout is 1 second + * Singleton + */ +var RequestManager = function (provider) { + // singleton pattern + if (arguments.callee._singletonInstance) { + return arguments.callee._singletonInstance; + } + arguments.callee._singletonInstance = this; + + this.provider = provider; + this.polls = {}; + this.timeout = null; + this.isPolling = false; +}; + +/** + * @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; + + if (this.provider && !this.isPolling) { + this.poll(); + this.isPolling = true; + } +}; + +/*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['poll_'+ pollId] = {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) { + delete this.polls['poll_'+ pollId]; +}; + +/** + * Should be called to reset the polling mechanism of the request manager + * + * @method reset + */ +RequestManager.prototype.reset = function () { + for (var key in this.polls) { + this.polls[key].uninstall(); + } + 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 () { + /*jshint maxcomplexity: 6 */ + this.timeout = setTimeout(this.poll.bind(this), c.ETH_POLLING_TIMEOUT); + + if (Object.keys(this.polls).length === 0) { + return; + } + + if (!this.provider) { + console.error(errors.InvalidProvider()); + return; + } + + var pollsData = []; + var pollsKeys = []; + for (var key in this.polls) { + pollsData.push(this.polls[key].data); + pollsKeys.push(key); + } + + if (pollsData.length === 0) { + return; + } + + var payload = Jsonrpc.getInstance().toBatchPayload(pollsData); + + 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) { + var key = pollsKeys[index]; + // make sure the filter is still installed after arrival of the request + if (self.polls[key]) { + result.callback = self.polls[key].callback; + return result; + } else + return false; + }).filter(function (result) { + return !!result; + }).filter(function (result) { + var valid = Jsonrpc.getInstance().isValidResponse(result); + if (!valid) { + result.callback(errors.InvalidResponse(result)); + } + return valid; + }).filter(function (result) { + return utils.isArray(result.result) && result.result.length > 0; + }).forEach(function (result) { + result.callback(null, result.result); + }); + }); +}; + +module.exports = RequestManager; + + +},{"../utils/config":5,"../utils/utils":7,"./errors":13,"./jsonrpc":21}],28:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file shh.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +var Method = require('./method'); +var formatters = require('./formatters'); + +var post = new Method({ + name: 'post', + call: 'shh_post', + params: 1, + inputFormatter: [formatters.inputPostFormatter] +}); + +var newIdentity = new Method({ + name: 'newIdentity', + call: 'shh_newIdentity', + params: 0 +}); + +var hasIdentity = new Method({ + name: 'hasIdentity', + call: 'shh_hasIdentity', + params: 1 +}); + +var newGroup = new Method({ + name: 'newGroup', + call: 'shh_newGroup', + params: 0 +}); + +var addToGroup = new Method({ + name: 'addToGroup', + call: 'shh_addToGroup', + params: 0 +}); + +var methods = [ + post, + newIdentity, + hasIdentity, + newGroup, + addToGroup +]; + +module.exports = { + methods: methods +}; + + +},{"./formatters":17,"./method":22}],29:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** + * @file transfer.js + * @author Marek Kotewicz + * @date 2015 + */ + +var web3 = require('../web3'); +var ICAP = require('./icap'); +var namereg = require('./namereg'); +var contract = require('./contract'); + +/** + * Should be used to make ICAP transfer + * + * @method transfer + * @param {String} iban number + * @param {String} from (address) + * @param {Value} value to be tranfered + * @param {Function} callback, callback + */ +var transfer = function (from, iban, value, callback) { + var icap = new ICAP(iban); + if (!icap.isValid()) { + throw new Error('invalid iban address'); + } + + if (icap.isDirect()) { + return transferToAddress(from, icap.address(), value, callback); + } + + if (!callback) { + var address = namereg.addr(icap.institution()); + return deposit(from, address, value, icap.client()); + } + + namereg.addr(icap.insitution(), function (err, address) { + return deposit(from, address, value, icap.client(), callback); + }); + +}; + +/** + * Should be used to transfer funds to certain address + * + * @method transferToAddress + * @param {String} address + * @param {String} from (address) + * @param {Value} value to be tranfered + * @param {Function} callback, callback + */ +var transferToAddress = function (from, address, value, callback) { + return web3.eth.sendTransaction({ + address: address, + from: from, + value: value + }, callback); +}; + +/** + * Should be used to deposit funds to generic Exchange contract (must implement deposit(bytes32) method!) + * + * @method deposit + * @param {String} address + * @param {String} from (address) + * @param {Value} value to be tranfered + * @param {String} client unique identifier + * @param {Function} callback, callback + */ +var deposit = function (from, address, value, client, callback) { + var abi = [{"constant":false,"inputs":[{"name":"name","type":"bytes32"}],"name":"deposit","outputs":[],"type":"function"}]; + return contract(abi).at(address).deposit(client, { + from: from, + value: value + }, callback); +}; + +module.exports = transfer; + + +},{"../web3":9,"./contract":11,"./icap":20,"./namereg":23}],30:[function(require,module,exports){ +/* + This file is part of ethereum.js. + + ethereum.js is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + ethereum.js is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with ethereum.js. If not, see . +*/ +/** @file watches.js + * @authors: + * Marek Kotewicz + * @date 2015 + */ + +var Method = require('./method'); + +/// @returns an array of objects describing web3.eth.filter api methods +var eth = function () { + var newFilterCall = function (args) { + var type = args[0]; + + switch(type) { + case 'latest': + args.shift(); + this.params = 0; + return 'eth_newBlockFilter'; + case 'pending': + args.shift(); + this.params = 0; + return 'eth_newPendingTransactionFilter'; + default: + return 'eth_newFilter'; + } + }; + + var newFilter = new Method({ + name: 'newFilter', + call: newFilterCall, + params: 1 + }); + + var uninstallFilter = new Method({ + name: 'uninstallFilter', + call: 'eth_uninstallFilter', + params: 1 + }); + + var getLogs = new Method({ + name: 'getLogs', + call: 'eth_getFilterLogs', + params: 1 + }); + + var poll = new Method({ + name: 'poll', + call: 'eth_getFilterChanges', + params: 1 + }); + + return [ + newFilter, + uninstallFilter, + getLogs, + poll + ]; +}; + +/// @returns an array of objects describing web3.shh.watch api methods +var shh = function () { + var newFilter = new Method({ + name: 'newFilter', + call: 'shh_newFilter', + params: 1 + }); + + var uninstallFilter = new Method({ + name: 'uninstallFilter', + call: 'shh_uninstallFilter', + params: 1 + }); + + var getLogs = new Method({ + name: 'getLogs', + call: 'shh_getMessages', + params: 1 + }); + + var poll = new Method({ + name: 'poll', + call: 'shh_getFilterChanges', + params: 1 + }); + + return [ + newFilter, + uninstallFilter, + getLogs, + poll + ]; +}; + +module.exports = { + eth: eth, + shh: shh +}; + + +},{"./method":22}],31:[function(require,module,exports){ + +},{}],32:[function(require,module,exports){ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(); + } + else if (typeof define === "function" && define.amd) { + // AMD + define([], factory); + } + else { + // Global (browser) + root.CryptoJS = factory(); + } +}(this, function () { + + /** + * CryptoJS core components. + */ + var CryptoJS = CryptoJS || (function (Math, undefined) { + /** + * CryptoJS namespace. + */ + var C = {}; + + /** + * Library namespace. + */ + var C_lib = C.lib = {}; + + /** + * Base object for prototypal inheritance. + */ + var Base = C_lib.Base = (function () { + function F() {} + + return { + /** + * Creates a new object that inherits from this object. + * + * @param {Object} overrides Properties to copy into the new object. + * + * @return {Object} The new object. + * + * @static + * + * @example + * + * var MyType = CryptoJS.lib.Base.extend({ + * field: 'value', + * + * method: function () { + * } + * }); + */ + extend: function (overrides) { + // Spawn + F.prototype = this; + var subtype = new F(); + + // Augment + if (overrides) { + subtype.mixIn(overrides); + } + + // Create default initializer + if (!subtype.hasOwnProperty('init')) { + subtype.init = function () { + subtype.$super.init.apply(this, arguments); + }; + } + + // Initializer's prototype is the subtype object + subtype.init.prototype = subtype; + + // Reference supertype + subtype.$super = this; + + return subtype; + }, + + /** + * Extends this object and runs the init method. + * Arguments to create() will be passed to init(). + * + * @return {Object} The new object. + * + * @static + * + * @example + * + * var instance = MyType.create(); + */ + create: function () { + var instance = this.extend(); + instance.init.apply(instance, arguments); + + return instance; + }, + + /** + * Initializes a newly created object. + * Override this method to add some logic when your objects are created. + * + * @example + * + * var MyType = CryptoJS.lib.Base.extend({ + * init: function () { + * // ... + * } + * }); + */ + init: function () { + }, + + /** + * Copies properties into this object. + * + * @param {Object} properties The properties to mix in. + * + * @example + * + * MyType.mixIn({ + * field: 'value' + * }); + */ + mixIn: function (properties) { + for (var propertyName in properties) { + if (properties.hasOwnProperty(propertyName)) { + this[propertyName] = properties[propertyName]; + } + } + + // IE won't copy toString using the loop above + if (properties.hasOwnProperty('toString')) { + this.toString = properties.toString; + } + }, + + /** + * Creates a copy of this object. + * + * @return {Object} The clone. + * + * @example + * + * var clone = instance.clone(); + */ + clone: function () { + return this.init.prototype.extend(this); + } + }; + }()); + + /** + * An array of 32-bit words. + * + * @property {Array} words The array of 32-bit words. + * @property {number} sigBytes The number of significant bytes in this word array. + */ + var WordArray = C_lib.WordArray = Base.extend({ + /** + * Initializes a newly created word array. + * + * @param {Array} words (Optional) An array of 32-bit words. + * @param {number} sigBytes (Optional) The number of significant bytes in the words. + * + * @example + * + * var wordArray = CryptoJS.lib.WordArray.create(); + * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]); + * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6); + */ + init: function (words, sigBytes) { + words = this.words = words || []; + + if (sigBytes != undefined) { + this.sigBytes = sigBytes; + } else { + this.sigBytes = words.length * 4; + } + }, + + /** + * Converts this word array to a string. + * + * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex + * + * @return {string} The stringified word array. + * + * @example + * + * var string = wordArray + ''; + * var string = wordArray.toString(); + * var string = wordArray.toString(CryptoJS.enc.Utf8); + */ + toString: function (encoder) { + return (encoder || Hex).stringify(this); + }, + + /** + * Concatenates a word array to this word array. + * + * @param {WordArray} wordArray The word array to append. + * + * @return {WordArray} This word array. + * + * @example + * + * wordArray1.concat(wordArray2); + */ + concat: function (wordArray) { + // Shortcuts + var thisWords = this.words; + var thatWords = wordArray.words; + var thisSigBytes = this.sigBytes; + var thatSigBytes = wordArray.sigBytes; + + // Clamp excess bits + this.clamp(); + + // Concat + if (thisSigBytes % 4) { + // Copy one byte at a time + for (var i = 0; i < thatSigBytes; i++) { + var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8); + } + } else { + // Copy one word at a time + for (var i = 0; i < thatSigBytes; i += 4) { + thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2]; + } + } + this.sigBytes += thatSigBytes; + + // Chainable + return this; + }, + + /** + * Removes insignificant bits. + * + * @example + * + * wordArray.clamp(); + */ + clamp: function () { + // Shortcuts + var words = this.words; + var sigBytes = this.sigBytes; + + // Clamp + words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8); + words.length = Math.ceil(sigBytes / 4); + }, + + /** + * Creates a copy of this word array. + * + * @return {WordArray} The clone. + * + * @example + * + * var clone = wordArray.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + clone.words = this.words.slice(0); + + return clone; + }, + + /** + * Creates a word array filled with random bytes. + * + * @param {number} nBytes The number of random bytes to generate. + * + * @return {WordArray} The random word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.lib.WordArray.random(16); + */ + random: function (nBytes) { + var words = []; + + var r = (function (m_w) { + var m_w = m_w; + var m_z = 0x3ade68b1; + var mask = 0xffffffff; + + return function () { + m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask; + m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask; + var result = ((m_z << 0x10) + m_w) & mask; + result /= 0x100000000; + result += 0.5; + return result * (Math.random() > .5 ? 1 : -1); + } + }); + + for (var i = 0, rcache; i < nBytes; i += 4) { + var _r = r((rcache || Math.random()) * 0x100000000); + + rcache = _r() * 0x3ade67b7; + words.push((_r() * 0x100000000) | 0); + } + + return new WordArray.init(words, nBytes); + } + }); + + /** + * Encoder namespace. + */ + var C_enc = C.enc = {}; + + /** + * Hex encoding strategy. + */ + var Hex = C_enc.Hex = { + /** + * Converts a word array to a hex string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The hex string. + * + * @static + * + * @example + * + * var hexString = CryptoJS.enc.Hex.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var hexChars = []; + for (var i = 0; i < sigBytes; i++) { + var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + hexChars.push((bite >>> 4).toString(16)); + hexChars.push((bite & 0x0f).toString(16)); + } + + return hexChars.join(''); + }, + + /** + * Converts a hex string to a word array. + * + * @param {string} hexStr The hex string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Hex.parse(hexString); + */ + parse: function (hexStr) { + // Shortcut + var hexStrLength = hexStr.length; + + // Convert + var words = []; + for (var i = 0; i < hexStrLength; i += 2) { + words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4); + } + + return new WordArray.init(words, hexStrLength / 2); + } + }; + + /** + * Latin1 encoding strategy. + */ + var Latin1 = C_enc.Latin1 = { + /** + * Converts a word array to a Latin1 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The Latin1 string. + * + * @static + * + * @example + * + * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray); + */ + stringify: function (wordArray) { + // Shortcuts + var words = wordArray.words; + var sigBytes = wordArray.sigBytes; + + // Convert + var latin1Chars = []; + for (var i = 0; i < sigBytes; i++) { + var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + latin1Chars.push(String.fromCharCode(bite)); + } + + return latin1Chars.join(''); + }, + + /** + * Converts a Latin1 string to a word array. + * + * @param {string} latin1Str The Latin1 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Latin1.parse(latin1String); + */ + parse: function (latin1Str) { + // Shortcut + var latin1StrLength = latin1Str.length; + + // Convert + var words = []; + for (var i = 0; i < latin1StrLength; i++) { + words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8); + } + + return new WordArray.init(words, latin1StrLength); + } + }; + + /** + * UTF-8 encoding strategy. + */ + var Utf8 = C_enc.Utf8 = { + /** + * Converts a word array to a UTF-8 string. + * + * @param {WordArray} wordArray The word array. + * + * @return {string} The UTF-8 string. + * + * @static + * + * @example + * + * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray); + */ + stringify: function (wordArray) { + try { + return decodeURIComponent(escape(Latin1.stringify(wordArray))); + } catch (e) { + throw new Error('Malformed UTF-8 data'); + } + }, + + /** + * Converts a UTF-8 string to a word array. + * + * @param {string} utf8Str The UTF-8 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Utf8.parse(utf8String); + */ + parse: function (utf8Str) { + return Latin1.parse(unescape(encodeURIComponent(utf8Str))); + } + }; + + /** + * Abstract buffered block algorithm template. + * + * The property blockSize must be implemented in a concrete subtype. + * + * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0 + */ + var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({ + /** + * Resets this block algorithm's data buffer to its initial state. + * + * @example + * + * bufferedBlockAlgorithm.reset(); + */ + reset: function () { + // Initial values + this._data = new WordArray.init(); + this._nDataBytes = 0; + }, + + /** + * Adds new data to this block algorithm's buffer. + * + * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8. + * + * @example + * + * bufferedBlockAlgorithm._append('data'); + * bufferedBlockAlgorithm._append(wordArray); + */ + _append: function (data) { + // Convert string to WordArray, else assume WordArray already + if (typeof data == 'string') { + data = Utf8.parse(data); + } + + // Append + this._data.concat(data); + this._nDataBytes += data.sigBytes; + }, + + /** + * Processes available data blocks. + * + * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype. + * + * @param {boolean} doFlush Whether all blocks and partial blocks should be processed. + * + * @return {WordArray} The processed data. + * + * @example + * + * var processedData = bufferedBlockAlgorithm._process(); + * var processedData = bufferedBlockAlgorithm._process(!!'flush'); + */ + _process: function (doFlush) { + // Shortcuts + var data = this._data; + var dataWords = data.words; + var dataSigBytes = data.sigBytes; + var blockSize = this.blockSize; + var blockSizeBytes = blockSize * 4; + + // Count blocks ready + var nBlocksReady = dataSigBytes / blockSizeBytes; + if (doFlush) { + // Round up to include partial blocks + nBlocksReady = Math.ceil(nBlocksReady); + } else { + // Round down to include only full blocks, + // less the number of blocks that must remain in the buffer + nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0); + } + + // Count words ready + var nWordsReady = nBlocksReady * blockSize; + + // Count bytes ready + var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes); + + // Process blocks + if (nWordsReady) { + for (var offset = 0; offset < nWordsReady; offset += blockSize) { + // Perform concrete-algorithm logic + this._doProcessBlock(dataWords, offset); + } + + // Remove processed words + var processedWords = dataWords.splice(0, nWordsReady); + data.sigBytes -= nBytesReady; + } + + // Return processed words + return new WordArray.init(processedWords, nBytesReady); + }, + + /** + * Creates a copy of this object. + * + * @return {Object} The clone. + * + * @example + * + * var clone = bufferedBlockAlgorithm.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + clone._data = this._data.clone(); + + return clone; + }, + + _minBufferSize: 0 + }); + + /** + * Abstract hasher template. + * + * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits) + */ + var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({ + /** + * Configuration options. + */ + cfg: Base.extend(), + + /** + * Initializes a newly created hasher. + * + * @param {Object} cfg (Optional) The configuration options to use for this hash computation. + * + * @example + * + * var hasher = CryptoJS.algo.SHA256.create(); + */ + init: function (cfg) { + // Apply config defaults + this.cfg = this.cfg.extend(cfg); + + // Set initial values + this.reset(); + }, + + /** + * Resets this hasher to its initial state. + * + * @example + * + * hasher.reset(); + */ + reset: function () { + // Reset data buffer + BufferedBlockAlgorithm.reset.call(this); + + // Perform concrete-hasher logic + this._doReset(); + }, + + /** + * Updates this hasher with a message. + * + * @param {WordArray|string} messageUpdate The message to append. + * + * @return {Hasher} This hasher. + * + * @example + * + * hasher.update('message'); + * hasher.update(wordArray); + */ + update: function (messageUpdate) { + // Append + this._append(messageUpdate); + + // Update the hash + this._process(); + + // Chainable + return this; + }, + + /** + * Finalizes the hash computation. + * Note that the finalize operation is effectively a destructive, read-once operation. + * + * @param {WordArray|string} messageUpdate (Optional) A final message update. + * + * @return {WordArray} The hash. + * + * @example + * + * var hash = hasher.finalize(); + * var hash = hasher.finalize('message'); + * var hash = hasher.finalize(wordArray); + */ + finalize: function (messageUpdate) { + // Final message update + if (messageUpdate) { + this._append(messageUpdate); + } + + // Perform concrete-hasher logic + var hash = this._doFinalize(); + + return hash; + }, + + blockSize: 512/32, + + /** + * Creates a shortcut function to a hasher's object interface. + * + * @param {Hasher} hasher The hasher to create a helper for. + * + * @return {Function} The shortcut function. + * + * @static + * + * @example + * + * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256); + */ + _createHelper: function (hasher) { + return function (message, cfg) { + return new hasher.init(cfg).finalize(message); + }; + }, + + /** + * Creates a shortcut function to the HMAC's object interface. + * + * @param {Hasher} hasher The hasher to use in this HMAC helper. + * + * @return {Function} The shortcut function. + * + * @static + * + * @example + * + * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256); + */ + _createHmacHelper: function (hasher) { + return function (message, key) { + return new C_algo.HMAC.init(hasher, key).finalize(message); + }; + } + }); + + /** + * Algorithm namespace. + */ + var C_algo = C.algo = {}; + + return C; + }(Math)); + + + return CryptoJS; + +})); +},{}],33:[function(require,module,exports){ +;(function (root, factory, undef) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core"), require("./x64-core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core", "./x64-core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function (Math) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var WordArray = C_lib.WordArray; + var Hasher = C_lib.Hasher; + var C_x64 = C.x64; + var X64Word = C_x64.Word; + var C_algo = C.algo; + + // Constants tables + var RHO_OFFSETS = []; + var PI_INDEXES = []; + var ROUND_CONSTANTS = []; + + // Compute Constants + (function () { + // Compute rho offset constants + var x = 1, y = 0; + for (var t = 0; t < 24; t++) { + RHO_OFFSETS[x + 5 * y] = ((t + 1) * (t + 2) / 2) % 64; + + var newX = y % 5; + var newY = (2 * x + 3 * y) % 5; + x = newX; + y = newY; + } + + // Compute pi index constants + for (var x = 0; x < 5; x++) { + for (var y = 0; y < 5; y++) { + PI_INDEXES[x + 5 * y] = y + ((2 * x + 3 * y) % 5) * 5; + } + } + + // Compute round constants + var LFSR = 0x01; + for (var i = 0; i < 24; i++) { + var roundConstantMsw = 0; + var roundConstantLsw = 0; + + for (var j = 0; j < 7; j++) { + if (LFSR & 0x01) { + var bitPosition = (1 << j) - 1; + if (bitPosition < 32) { + roundConstantLsw ^= 1 << bitPosition; + } else /* if (bitPosition >= 32) */ { + roundConstantMsw ^= 1 << (bitPosition - 32); + } + } + + // Compute next LFSR + if (LFSR & 0x80) { + // Primitive polynomial over GF(2): x^8 + x^6 + x^5 + x^4 + 1 + LFSR = (LFSR << 1) ^ 0x71; + } else { + LFSR <<= 1; + } + } + + ROUND_CONSTANTS[i] = X64Word.create(roundConstantMsw, roundConstantLsw); + } + }()); + + // Reusable objects for temporary values + var T = []; + (function () { + for (var i = 0; i < 25; i++) { + T[i] = X64Word.create(); + } + }()); + + /** + * SHA-3 hash algorithm. + */ + var SHA3 = C_algo.SHA3 = Hasher.extend({ + /** + * Configuration options. + * + * @property {number} outputLength + * The desired number of bits in the output hash. + * Only values permitted are: 224, 256, 384, 512. + * Default: 512 + */ + cfg: Hasher.cfg.extend({ + outputLength: 512 + }), + + _doReset: function () { + var state = this._state = [] + for (var i = 0; i < 25; i++) { + state[i] = new X64Word.init(); + } + + this.blockSize = (1600 - 2 * this.cfg.outputLength) / 32; + }, + + _doProcessBlock: function (M, offset) { + // Shortcuts + var state = this._state; + var nBlockSizeLanes = this.blockSize / 2; + + // Absorb + for (var i = 0; i < nBlockSizeLanes; i++) { + // Shortcuts + var M2i = M[offset + 2 * i]; + var M2i1 = M[offset + 2 * i + 1]; + + // Swap endian + M2i = ( + (((M2i << 8) | (M2i >>> 24)) & 0x00ff00ff) | + (((M2i << 24) | (M2i >>> 8)) & 0xff00ff00) + ); + M2i1 = ( + (((M2i1 << 8) | (M2i1 >>> 24)) & 0x00ff00ff) | + (((M2i1 << 24) | (M2i1 >>> 8)) & 0xff00ff00) + ); + + // Absorb message into state + var lane = state[i]; + lane.high ^= M2i1; + lane.low ^= M2i; + } + + // Rounds + for (var round = 0; round < 24; round++) { + // Theta + for (var x = 0; x < 5; x++) { + // Mix column lanes + var tMsw = 0, tLsw = 0; + for (var y = 0; y < 5; y++) { + var lane = state[x + 5 * y]; + tMsw ^= lane.high; + tLsw ^= lane.low; + } + + // Temporary values + var Tx = T[x]; + Tx.high = tMsw; + Tx.low = tLsw; + } + for (var x = 0; x < 5; x++) { + // Shortcuts + var Tx4 = T[(x + 4) % 5]; + var Tx1 = T[(x + 1) % 5]; + var Tx1Msw = Tx1.high; + var Tx1Lsw = Tx1.low; + + // Mix surrounding columns + var tMsw = Tx4.high ^ ((Tx1Msw << 1) | (Tx1Lsw >>> 31)); + var tLsw = Tx4.low ^ ((Tx1Lsw << 1) | (Tx1Msw >>> 31)); + for (var y = 0; y < 5; y++) { + var lane = state[x + 5 * y]; + lane.high ^= tMsw; + lane.low ^= tLsw; + } + } + + // Rho Pi + for (var laneIndex = 1; laneIndex < 25; laneIndex++) { + // Shortcuts + var lane = state[laneIndex]; + var laneMsw = lane.high; + var laneLsw = lane.low; + var rhoOffset = RHO_OFFSETS[laneIndex]; + + // Rotate lanes + if (rhoOffset < 32) { + var tMsw = (laneMsw << rhoOffset) | (laneLsw >>> (32 - rhoOffset)); + var tLsw = (laneLsw << rhoOffset) | (laneMsw >>> (32 - rhoOffset)); + } else /* if (rhoOffset >= 32) */ { + var tMsw = (laneLsw << (rhoOffset - 32)) | (laneMsw >>> (64 - rhoOffset)); + var tLsw = (laneMsw << (rhoOffset - 32)) | (laneLsw >>> (64 - rhoOffset)); + } + + // Transpose lanes + var TPiLane = T[PI_INDEXES[laneIndex]]; + TPiLane.high = tMsw; + TPiLane.low = tLsw; + } + + // Rho pi at x = y = 0 + var T0 = T[0]; + var state0 = state[0]; + T0.high = state0.high; + T0.low = state0.low; + + // Chi + for (var x = 0; x < 5; x++) { + for (var y = 0; y < 5; y++) { + // Shortcuts + var laneIndex = x + 5 * y; + var lane = state[laneIndex]; + var TLane = T[laneIndex]; + var Tx1Lane = T[((x + 1) % 5) + 5 * y]; + var Tx2Lane = T[((x + 2) % 5) + 5 * y]; + + // Mix rows + lane.high = TLane.high ^ (~Tx1Lane.high & Tx2Lane.high); + lane.low = TLane.low ^ (~Tx1Lane.low & Tx2Lane.low); + } + } + + // Iota + var lane = state[0]; + var roundConstant = ROUND_CONSTANTS[round]; + lane.high ^= roundConstant.high; + lane.low ^= roundConstant.low;; + } + }, + + _doFinalize: function () { + // Shortcuts + var data = this._data; + var dataWords = data.words; + var nBitsTotal = this._nDataBytes * 8; + var nBitsLeft = data.sigBytes * 8; + var blockSizeBits = this.blockSize * 32; + + // Add padding + dataWords[nBitsLeft >>> 5] |= 0x1 << (24 - nBitsLeft % 32); + dataWords[((Math.ceil((nBitsLeft + 1) / blockSizeBits) * blockSizeBits) >>> 5) - 1] |= 0x80; + data.sigBytes = dataWords.length * 4; + + // Hash final blocks + this._process(); + + // Shortcuts + var state = this._state; + var outputLengthBytes = this.cfg.outputLength / 8; + var outputLengthLanes = outputLengthBytes / 8; + + // Squeeze + var hashWords = []; + for (var i = 0; i < outputLengthLanes; i++) { + // Shortcuts + var lane = state[i]; + var laneMsw = lane.high; + var laneLsw = lane.low; + + // Swap endian + laneMsw = ( + (((laneMsw << 8) | (laneMsw >>> 24)) & 0x00ff00ff) | + (((laneMsw << 24) | (laneMsw >>> 8)) & 0xff00ff00) + ); + laneLsw = ( + (((laneLsw << 8) | (laneLsw >>> 24)) & 0x00ff00ff) | + (((laneLsw << 24) | (laneLsw >>> 8)) & 0xff00ff00) + ); + + // Squeeze state to retrieve hash + hashWords.push(laneLsw); + hashWords.push(laneMsw); + } + + // Return final computed hash + return new WordArray.init(hashWords, outputLengthBytes); + }, + + clone: function () { + var clone = Hasher.clone.call(this); + + var state = clone._state = this._state.slice(0); + for (var i = 0; i < 25; i++) { + state[i] = state[i].clone(); + } + + return clone; + } + }); + + /** + * Shortcut function to the hasher's object interface. + * + * @param {WordArray|string} message The message to hash. + * + * @return {WordArray} The hash. + * + * @static + * + * @example + * + * var hash = CryptoJS.SHA3('message'); + * var hash = CryptoJS.SHA3(wordArray); + */ + C.SHA3 = Hasher._createHelper(SHA3); + + /** + * Shortcut function to the HMAC's object interface. + * + * @param {WordArray|string} message The message to hash. + * @param {WordArray|string} key The secret key. + * + * @return {WordArray} The HMAC. + * + * @static + * + * @example + * + * var hmac = CryptoJS.HmacSHA3(message, key); + */ + C.HmacSHA3 = Hasher._createHmacHelper(SHA3); + }(Math)); + + + return CryptoJS.SHA3; + +})); +},{"./core":32,"./x64-core":34}],34:[function(require,module,exports){ +;(function (root, factory) { + if (typeof exports === "object") { + // CommonJS + module.exports = exports = factory(require("./core")); + } + else if (typeof define === "function" && define.amd) { + // AMD + define(["./core"], factory); + } + else { + // Global (browser) + factory(root.CryptoJS); + } +}(this, function (CryptoJS) { + + (function (undefined) { + // Shortcuts + var C = CryptoJS; + var C_lib = C.lib; + var Base = C_lib.Base; + var X32WordArray = C_lib.WordArray; + + /** + * x64 namespace. + */ + var C_x64 = C.x64 = {}; + + /** + * A 64-bit word. + */ + var X64Word = C_x64.Word = Base.extend({ + /** + * Initializes a newly created 64-bit word. + * + * @param {number} high The high 32 bits. + * @param {number} low The low 32 bits. + * + * @example + * + * var x64Word = CryptoJS.x64.Word.create(0x00010203, 0x04050607); + */ + init: function (high, low) { + this.high = high; + this.low = low; + } + + /** + * Bitwise NOTs this word. + * + * @return {X64Word} A new x64-Word object after negating. + * + * @example + * + * var negated = x64Word.not(); + */ + // not: function () { + // var high = ~this.high; + // var low = ~this.low; + + // return X64Word.create(high, low); + // }, + + /** + * Bitwise ANDs this word with the passed word. + * + * @param {X64Word} word The x64-Word to AND with this word. + * + * @return {X64Word} A new x64-Word object after ANDing. + * + * @example + * + * var anded = x64Word.and(anotherX64Word); + */ + // and: function (word) { + // var high = this.high & word.high; + // var low = this.low & word.low; + + // return X64Word.create(high, low); + // }, + + /** + * Bitwise ORs this word with the passed word. + * + * @param {X64Word} word The x64-Word to OR with this word. + * + * @return {X64Word} A new x64-Word object after ORing. + * + * @example + * + * var ored = x64Word.or(anotherX64Word); + */ + // or: function (word) { + // var high = this.high | word.high; + // var low = this.low | word.low; + + // return X64Word.create(high, low); + // }, + + /** + * Bitwise XORs this word with the passed word. + * + * @param {X64Word} word The x64-Word to XOR with this word. + * + * @return {X64Word} A new x64-Word object after XORing. + * + * @example + * + * var xored = x64Word.xor(anotherX64Word); + */ + // xor: function (word) { + // var high = this.high ^ word.high; + // var low = this.low ^ word.low; + + // return X64Word.create(high, low); + // }, + + /** + * Shifts this word n bits to the left. + * + * @param {number} n The number of bits to shift. + * + * @return {X64Word} A new x64-Word object after shifting. + * + * @example + * + * var shifted = x64Word.shiftL(25); + */ + // shiftL: function (n) { + // if (n < 32) { + // var high = (this.high << n) | (this.low >>> (32 - n)); + // var low = this.low << n; + // } else { + // var high = this.low << (n - 32); + // var low = 0; + // } + + // return X64Word.create(high, low); + // }, + + /** + * Shifts this word n bits to the right. + * + * @param {number} n The number of bits to shift. + * + * @return {X64Word} A new x64-Word object after shifting. + * + * @example + * + * var shifted = x64Word.shiftR(7); + */ + // shiftR: function (n) { + // if (n < 32) { + // var low = (this.low >>> n) | (this.high << (32 - n)); + // var high = this.high >>> n; + // } else { + // var low = this.high >>> (n - 32); + // var high = 0; + // } + + // return X64Word.create(high, low); + // }, + + /** + * Rotates this word n bits to the left. + * + * @param {number} n The number of bits to rotate. + * + * @return {X64Word} A new x64-Word object after rotating. + * + * @example + * + * var rotated = x64Word.rotL(25); + */ + // rotL: function (n) { + // return this.shiftL(n).or(this.shiftR(64 - n)); + // }, + + /** + * Rotates this word n bits to the right. + * + * @param {number} n The number of bits to rotate. + * + * @return {X64Word} A new x64-Word object after rotating. + * + * @example + * + * var rotated = x64Word.rotR(7); + */ + // rotR: function (n) { + // return this.shiftR(n).or(this.shiftL(64 - n)); + // }, + + /** + * Adds this word with the passed word. + * + * @param {X64Word} word The x64-Word to add with this word. + * + * @return {X64Word} A new x64-Word object after adding. + * + * @example + * + * var added = x64Word.add(anotherX64Word); + */ + // add: function (word) { + // var low = (this.low + word.low) | 0; + // var carry = (low >>> 0) < (this.low >>> 0) ? 1 : 0; + // var high = (this.high + word.high + carry) | 0; + + // return X64Word.create(high, low); + // } + }); + + /** + * An array of 64-bit words. + * + * @property {Array} words The array of CryptoJS.x64.Word objects. + * @property {number} sigBytes The number of significant bytes in this word array. + */ + var X64WordArray = C_x64.WordArray = Base.extend({ + /** + * Initializes a newly created word array. + * + * @param {Array} words (Optional) An array of CryptoJS.x64.Word objects. + * @param {number} sigBytes (Optional) The number of significant bytes in the words. + * + * @example + * + * var wordArray = CryptoJS.x64.WordArray.create(); + * + * var wordArray = CryptoJS.x64.WordArray.create([ + * CryptoJS.x64.Word.create(0x00010203, 0x04050607), + * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f) + * ]); + * + * var wordArray = CryptoJS.x64.WordArray.create([ + * CryptoJS.x64.Word.create(0x00010203, 0x04050607), + * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f) + * ], 10); + */ + init: function (words, sigBytes) { + words = this.words = words || []; + + if (sigBytes != undefined) { + this.sigBytes = sigBytes; + } else { + this.sigBytes = words.length * 8; + } + }, + + /** + * Converts this 64-bit word array to a 32-bit word array. + * + * @return {CryptoJS.lib.WordArray} This word array's data as a 32-bit word array. + * + * @example + * + * var x32WordArray = x64WordArray.toX32(); + */ + toX32: function () { + // Shortcuts + var x64Words = this.words; + var x64WordsLength = x64Words.length; + + // Convert + var x32Words = []; + for (var i = 0; i < x64WordsLength; i++) { + var x64Word = x64Words[i]; + x32Words.push(x64Word.high); + x32Words.push(x64Word.low); + } + + return X32WordArray.create(x32Words, this.sigBytes); + }, + + /** + * Creates a copy of this word array. + * + * @return {X64WordArray} The clone. + * + * @example + * + * var clone = x64WordArray.clone(); + */ + clone: function () { + var clone = Base.clone.call(this); + + // Clone "words" array + var words = clone.words = this.words.slice(0); + + // Clone each X64Word object + var wordsLength = words.length; + for (var i = 0; i < wordsLength; i++) { + words[i] = words[i].clone(); + } + + return clone; + } + }); + }()); + + + return CryptoJS; + +})); +},{"./core":32}],"bignumber.js":[function(require,module,exports){ +'use strict'; + +module.exports = BigNumber; // jshint ignore:line + + +},{}],"web3":[function(require,module,exports){ +var web3 = require('./lib/web3'); +web3.providers.HttpProvider = require('./lib/web3/httpprovider'); +web3.providers.QtSyncProvider = require('./lib/web3/qtsync'); +web3.eth.contract = require('./lib/web3/contract'); +web3.eth.namereg = require('./lib/web3/namereg'); +web3.eth.sendIBANTransaction = require('./lib/web3/transfer'); + +// dont override global variable +if (typeof window !== 'undefined' && typeof window.web3 === 'undefined') { + window.web3 = web3; +} + +module.exports = web3; + + +},{"./lib/web3":9,"./lib/web3/contract":11,"./lib/web3/httpprovider":19,"./lib/web3/namereg":23,"./lib/web3/qtsync":26,"./lib/web3/transfer":29}]},{},["web3"]) +//# sourceMappingURL=web3-light.js.map diff --git a/libjsqrc/ethereumjs/dist/web3-light.min.js b/libjsqrc/ethereumjs/dist/web3-light.min.js new file mode 100644 index 000000000..962e16e5f --- /dev/null +++ b/libjsqrc/ethereumjs/dist/web3-light.min.js @@ -0,0 +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":7,"./formatters":2,"./param":3,"bignumber.js":"bignumber.js"}],2:[function(t,e,n){var r=t("bignumber.js"),o=t("../utils/utils"),i=t("../utils/config"),a=t("./param"),s=function(t){var e=2*i.ETH_PADDING;r.config(i.ETH_BIGNUMBER_ROUNDING_MODE);var n=o.padLeft(o.toTwosComplement(t).round().toString(16),e);return new a(n)},u=function(t){var e=o.fromAscii(t,i.ETH_PADDING).substr(2);return new a(e)},c=function(t){var e=o.fromAscii(t,i.ETH_PADDING).substr(2);return new a(s(t.length).value+e,32)},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":7,"./param":3,"bignumber.js":"bignumber.js"}],3:[function(t,e,n){var r=t("../utils/utils"),o=function(t,e){this.value=t||"",this.offset=e};o.prototype.dynamicPartLength=function(){return this.dynamicPart().length/2},o.prototype.withOffset=function(t){return new o(this.value,t)},o.prototype.combine=function(t){return new o(this.value+t.value)},o.prototype.isDynamic=function(){return this.value.length>64||void 0!==this.offset},o.prototype.offsetAsBytes=function(){return this.isDynamic()?r.padLeft(r.toTwosComplement(this.offset).toString(16),64):""},o.prototype.staticPart=function(){return this.isDynamic()?this.offsetAsBytes():this.value},o.prototype.dynamicPart=function(){return this.isDynamic()?this.value:""},o.prototype.encode=function(){return this.staticPart()+this.dynamicPart()},o.encodeList=function(t){var e=32*t.length,n=t.map(function(t){if(!t.isDynamic())return t;var n=e;return e+=t.dynamicPartLength(),t.withOffset(n)});return n.reduce(function(t,e){return t+e.dynamicPart()},n.reduce(function(t,e){return t+e.staticPart()},""))},o.decodeParam=function(t,e){return e=e||0,new o(t.substr(64*e,64))};var i=function(t,e){return parseInt("0x"+t.substr(64*e,64))};o.decodeBytes=function(t,e){e=e||0;var n=i(t,e);return new o(t.substr(2*n,128),0)},o.decodeArray=function(t,e){e=e||0;var n=i(t,e),r=parseInt("0x"+t.substr(2*n,64));return new o(t.substr(2*n,64*(r+1)),0)},e.exports=o},{"../utils/utils":7}],4:[function(t,e,n){"use strict";n.XMLHttpRequest="undefined"==typeof XMLHttpRequest?{}:XMLHttpRequest},{}],5:[function(t,e,n){var r=t("bignumber.js"),o=["wei","kwei","Mwei","Gwei","szabo","finney","femtoether","picoether","nanoether","microether","milliether","nano","micro","milli","ether","grand","Mether","Gether","Tether","Pether","Eether","Zether","Yether","Nether","Dether","Vether","Uether"];e.exports={ETH_PADDING:32,ETH_SIGNATURE_LENGTH:4,ETH_UNITS:o,ETH_BIGNUMBER_ROUNDING_MODE:{ROUNDING_MODE:r.ROUND_DOWN},ETH_POLLING_TIMEOUT:500,defaultBlock:"latest",defaultAccount:void 0}},{"bignumber.js":"bignumber.js"}],6:[function(t,e,n){var r=t("./utils"),o=t("crypto-js/sha3");e.exports=function(t,e){return"0x"!==t.substr(0,2)||e||(console.warn("requirement of using web3.fromAscii before sha3 is deprecated"),console.warn("new usage: 'web3.sha3(\"hello\")'"),console.warn("see https://github.com/ethereum/web3.js/pull/205"),console.warn("if you need to hash hex value, you can do 'sha3(\"0xfff\", true)'"),t=r.toAscii(t)),o(t,{outputLength:256}).toString()}},{"./utils":7,"crypto-js/sha3":33}],7:[function(t,e,n){var r=t("bignumber.js"),o={wei:"1",kwei:"1000",ada:"1000",femtoether:"1000",mwei:"1000000",babbage:"1000000",picoether:"1000000",gwei:"1000000000",shannon:"1000000000",nanoether:"1000000000",nano:"1000000000",szabo:"1000000000000",microether:"1000000000000",micro:"1000000000000",finney:"1000000000000000",milliether:"1000000000000000",milli:"1000000000000000",ether:"1000000000000000000",kether:"1000000000000000000000",grand:"1000000000000000000000",einstein:"1000000000000000000000",mether:"1000000000000000000000000",gether:"1000000000000000000000000000",tether:"1000000000000000000000000000000"},i=function(t,e,n){return new Array(e-t.length+1).join(n?n:"0")+t},a=function(t){var e="",n=0,r=t.length;for("0x"===t.substring(0,2)&&(n=2);r>n;n+=2){var o=parseInt(t.substr(n,2),16);if(0===o)break;e+=String.fromCharCode(o)}return e},s=function(t){for(var e="",n=0;nthis._inputTypes.length&&!i.isObject(t[t.length-1])?a.inputDefaultBlockNumberFormatter(t.pop()):void 0},u.prototype.toPayload=function(t){var e={};return t.length>this._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},u.prototype.signature=function(){return s(this._name).slice(0,8)},u.prototype.unpackOutput=function(t){if(t){t=t.length>=2?t.slice(2):t;var e=o.decodeParams(this._outputTypes,t);return 1===e.length?e[0]:e}},u.prototype.call=function(){var t=Array.prototype.slice.call(arguments).filter(function(t){return void 0!==t}),e=this.extractCallback(t),n=this.extractDefaultBlock(t),o=this.toPayload(t);if(!e){var i=r.eth.call(o,n);return this.unpackOutput(i)}var a=this;r.eth.call(o,n,function(t,n){e(t,a.unpackOutput(n))})},u.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)},u.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)},u.prototype.displayName=function(){return i.extractDisplayName(this._name)},u.prototype.typeName=function(){return i.extractTypeName(this._name)},u.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}},u.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))},u.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=u},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9,"./formatters":17}],19:[function(t,e,n){"use strict";var r=t("xmlhttprequest").XMLHttpRequest,o=t("./errors"),i=function(t){this.host=t||"http://localhost:8545"};i.prototype.send=function(t){var e=new r;e.open("POST",this.host,!1),e.setRequestHeader("Content-type","application/json");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),n.setRequestHeader("Content-type","application/json");try{n.send(JSON.stringify(t))}catch(i){e(o.InvalidConnection(this.host))}},e.exports=i},{"./errors":13,xmlhttprequest:4}],20:[function(t,e,n){var r=t("../utils/utils"),o=function(t){this._iban=t};o.prototype.isValid=function(){return r.isIBAN(this._iban)},o.prototype.isDirect=function(){return 34===this._iban.length},o.prototype.isIndirect=function(){return 20===this._iban.length},o.prototype.checksum=function(){return this._iban.substr(2,2)},o.prototype.institution=function(){return this.isIndirect()?this._iban.substr(7,4):""},o.prototype.client=function(){return this.isIndirect()?this._iban.substr(11):""},o.prototype.address=function(){return this.isDirect()?this._iban.substr(4):""},e.exports=o},{"../utils/utils":7}],21:[function(t,e,n){var r=function(){return arguments.callee._singletonInstance?arguments.callee._singletonInstance:(arguments.callee._singletonInstance=this,void(this.messageId=1))};r.getInstance=function(){var t=new r;return t},r.prototype.toPayload=function(t,e){return t||console.error("jsonrpc method should be specified!"),{jsonrpc:"2.0",method:t,params:e||[],id:this.messageId++}},r.prototype.isValidResponse=function(t){return!!t&&!t.error&&"2.0"===t.jsonrpc&&"number"==typeof t.id&&void 0!==t.result},r.prototype.toBatchPayload=function(t){var e=this;return t.map(function(t){return e.toPayload(t.method,t.params)})},e.exports=r},{}],22:[function(t,e,n){var r=t("./requestmanager"),o=t("../utils/utils"),i=t("./errors"),a=function(t){this.name=t.name,this.call=t.call,this.params=t.params||0,this.inputFormatter=t.inputFormatter,this.outputFormatter=t.outputFormatter};a.prototype.getCall=function(t){return o.isFunction(this.call)?this.call(t):this.call},a.prototype.extractCallback=function(t){return o.isFunction(t[t.length-1])?t.pop():void 0},a.prototype.validateArgs=function(t){if(t.length!==this.params)throw i.InvalidNumberOfParams()},a.prototype.formatInput=function(t){return this.inputFormatter?this.inputFormatter.map(function(e,n){return e?e(t[n]):t[n]}):t},a.prototype.formatOutput=function(t){return this.outputFormatter&&null!==t?this.outputFormatter(t):t},a.prototype.attachToObject=function(t){var e=this.send.bind(this);e.request=this.request.bind(this),e.call=this.call;var n=this.name.split(".");n.length>1?(t[n[0]]=t[n[0]]||{},t[n[0]][n[1]]=e):t[n[0]]=e},a.prototype.toPayload=function(t){var e=this.getCall(t),n=this.extractCallback(t),r=this.formatInput(t);return this.validateArgs(r),{method:e,params:r,callback:n}},a.prototype.request=function(){var t=this.toPayload(Array.prototype.slice.call(arguments));return t.format=this.formatOutput.bind(this),t},a.prototype.send=function(){var t=this.toPayload(Array.prototype.slice.call(arguments));if(t.callback){var e=this;return r.getInstance().sendAsync(t,function(n,r){t.callback(n,e.formatOutput(r))})}return this.formatOutput(r.getInstance().send(t))},e.exports=a},{"../utils/utils":7,"./errors":13,"./requestmanager":27}],23:[function(t,e,n){var r=t("./contract"),o="0xc6d9d2cd449a754c494264e1809c50e34d64562b",i=[{constant:!0,inputs:[{name:"_owner",type:"address"}],name:"name",outputs:[{name:"o_name",type:"bytes32"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"owner",outputs:[{name:"",type:"address"}],type:"function"},{constant:!0, +inputs:[{name:"_name",type:"bytes32"}],name:"content",outputs:[{name:"",type:"bytes32"}],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"addr",outputs:[{name:"",type:"address"}],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"}],name:"reserve",outputs:[],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"subRegistrar",outputs:[{name:"o_subRegistrar",type:"address"}],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_newOwner",type:"address"}],name:"transfer",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_registrar",type:"address"}],name:"setSubRegistrar",outputs:[],type:"function"},{constant:!1,inputs:[],name:"Registrar",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_a",type:"address"},{name:"_primary",type:"bool"}],name:"setAddress",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"},{name:"_content",type:"bytes32"}],name:"setContent",outputs:[],type:"function"},{constant:!1,inputs:[{name:"_name",type:"bytes32"}],name:"disown",outputs:[],type:"function"},{constant:!0,inputs:[{name:"_name",type:"bytes32"}],name:"register",outputs:[{name:"",type:"address"}],type:"function"},{anonymous:!1,inputs:[{indexed:!0,name:"name",type:"bytes32"}],name:"Changed",type:"event"},{anonymous:!1,inputs:[{indexed:!0,name:"name",type:"bytes32"},{indexed:!0,name:"addr",type:"address"}],name:"PrimaryChanged",type:"event"}];e.exports=r(i).at(o)},{"./contract":11}],24:[function(t,e,n){var r=t("../utils/utils"),o=t("./property"),i=[],a=[new o({name:"listening",getter:"net_listening"}),new o({name:"peerCount",getter:"net_peerCount",outputFormatter:r.toDecimal})];e.exports={methods:i,properties:a}},{"../utils/utils":7,"./property":25}],25:[function(t,e,n){var r=t("./requestmanager"),o=function(t){this.name=t.name,this.getter=t.getter,this.setter=t.setter,this.outputFormatter=t.outputFormatter,this.inputFormatter=t.inputFormatter};o.prototype.formatInput=function(t){return this.inputFormatter?this.inputFormatter(t):t},o.prototype.formatOutput=function(t){return this.outputFormatter&&null!==t?this.outputFormatter(t):t},o.prototype.attachToObject=function(t){var e={get:this.get.bind(this)},n=this.name.split("."),r=n[0];n.length>1&&(t[n[0]]=t[n[0]]||{},t=t[n[0]],r=n[1]),Object.defineProperty(t,r,e);var o=function(t,e){return t+e.charAt(0).toUpperCase()+e.slice(1)};t[o("get",r)]=this.getAsync.bind(this)},o.prototype.get=function(){return this.formatOutput(r.getInstance().send({method:this.getter}))},o.prototype.getAsync=function(t){var e=this;r.getInstance().sendAsync({method:this.getter},function(n,r){return n?t(n):void t(n,e.formatOutput(r))})},e.exports=o},{"./requestmanager":27}],26:[function(t,e,n){var r=function(){};r.prototype.send=function(t){var e=navigator.qt.callMethod(JSON.stringify(t));return JSON.parse(e)},e.exports=r},{}],27:[function(t,e,n){var r=t("./jsonrpc"),o=t("../utils/utils"),i=t("../utils/config"),a=t("./errors"),s=function(t){return arguments.callee._singletonInstance?arguments.callee._singletonInstance:(arguments.callee._singletonInstance=this,this.provider=t,this.polls={},this.timeout=null,void(this.isPolling=!1))};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,this.provider&&!this.isPolling&&(this.poll(),this.isPolling=!0)},s.prototype.startPolling=function(t,e,n,r){this.polls["poll_"+e]={data:t,id:e,callback:n,uninstall:r}},s.prototype.stopPolling=function(t){delete this.polls["poll_"+t]},s.prototype.reset=function(){for(var t in this.polls)this.polls[t].uninstall();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),0!==Object.keys(this.polls).length){if(!this.provider)return void console.error(a.InvalidProvider());var t=[],e=[];for(var n in this.polls)t.push(this.polls[n].data),e.push(n);if(0!==t.length){var s=r.getInstance().toBatchPayload(t),u=this;this.provider.sendAsync(s,function(t,n){if(!t){if(!o.isArray(n))throw a.InvalidResponse(n);n.map(function(t,n){var r=e[n];return u.polls[r]?(t.callback=u.polls[r].callback,t):!1}).filter(function(t){return!!t}).filter(function(t){var e=r.getInstance().isValidResponse(t);return e||t.callback(a.InvalidResponse(t)),e}).filter(function(t){return o.isArray(t.result)&&t.result.length>0}).forEach(function(t){t.callback(null,t.result)})}})}}},e.exports=s},{"../utils/config":5,"../utils/utils":7,"./errors":13,"./jsonrpc":21}],28:[function(t,e,n){var r=t("./method"),o=t("./formatters"),i=new r({name:"post",call:"shh_post",params:1,inputFormatter:[o.inputPostFormatter]}),a=new r({name:"newIdentity",call:"shh_newIdentity",params:0}),s=new r({name:"hasIdentity",call:"shh_hasIdentity",params:1}),u=new r({name:"newGroup",call:"shh_newGroup",params:0}),c=new r({name:"addToGroup",call:"shh_addToGroup",params:0}),l=[i,a,s,u,c];e.exports={methods:l}},{"./formatters":17,"./method":22}],29:[function(t,e,n){var r=t("../web3"),o=t("./icap"),i=t("./namereg"),a=t("./contract"),s=function(t,e,n,r){var a=new o(e);if(!a.isValid())throw new Error("invalid iban address");if(a.isDirect())return u(t,a.address(),n,r);if(!r){var s=i.addr(a.institution());return c(t,s,n,a.client())}i.addr(a.insitution(),function(e,o){return c(t,o,n,a.client(),r)})},u=function(t,e,n,o){return r.eth.sendTransaction({address:e,from:t,value:n},o)},c=function(t,e,n,r,o){var i=[{constant:!1,inputs:[{name:"name",type:"bytes32"}],name:"deposit",outputs:[],type:"function"}];return a(i).at(e).deposit(r,{from:t,value:n},o)};e.exports=s},{"../web3":9,"./contract":11,"./icap":20,"./namereg":23}],30:[function(t,e,n){var r=t("./method"),o=function(){var t=function(t){var e=t[0];switch(e){case"latest":return t.shift(),this.params=0,"eth_newBlockFilter";case"pending":return t.shift(),this.params=0,"eth_newPendingTransactionFilter";default:return"eth_newFilter"}},e=new r({name:"newFilter",call:t,params:1}),n=new r({name:"uninstallFilter",call:"eth_uninstallFilter",params:1}),o=new r({name:"getLogs",call:"eth_getFilterLogs",params:1}),i=new r({name:"poll",call:"eth_getFilterChanges",params:1});return[e,n,o,i]},i=function(){var t=new r({name:"newFilter",call:"shh_newFilter",params:1}),e=new r({name:"uninstallFilter",call:"shh_uninstallFilter",params:1}),n=new r({name:"getLogs",call:"shh_getMessages",params:1}),o=new r({name:"poll",call:"shh_getFilterChanges",params:1});return[t,e,n,o]};e.exports={eth:o,shh:i}},{"./method":22}],31:[function(t,e,n){},{}],32:[function(t,e,n){!function(t,r){"object"==typeof n?e.exports=n=r():"function"==typeof define&&define.amd?define([],r):t.CryptoJS=r()}(this,function(){var t=t||function(t,e){var n={},r=n.lib={},o=r.Base=function(){function t(){}return{extend:function(e){t.prototype=this;var n=new t;return e&&n.mixIn(e),n.hasOwnProperty("init")||(n.init=function(){n.$super.init.apply(this,arguments)}),n.init.prototype=n,n.$super=this,n},create:function(){var t=this.extend();return t.init.apply(t,arguments),t},init:function(){},mixIn:function(t){for(var e in t)t.hasOwnProperty(e)&&(this[e]=t[e]);t.hasOwnProperty("toString")&&(this.toString=t.toString)},clone:function(){return this.init.prototype.extend(this)}}}(),i=r.WordArray=o.extend({init:function(t,n){t=this.words=t||[],this.sigBytes=n!=e?n:4*t.length},toString:function(t){return(t||s).stringify(this)},concat:function(t){var e=this.words,n=t.words,r=this.sigBytes,o=t.sigBytes;if(this.clamp(),r%4)for(var i=0;o>i;i++){var a=n[i>>>2]>>>24-i%4*8&255;e[r+i>>>2]|=a<<24-(r+i)%4*8}else for(var i=0;o>i;i+=4)e[r+i>>>2]=n[i>>>2];return this.sigBytes+=o,this},clamp:function(){var e=this.words,n=this.sigBytes;e[n>>>2]&=4294967295<<32-n%4*8,e.length=t.ceil(n/4)},clone:function(){var t=o.clone.call(this);return t.words=this.words.slice(0),t},random:function(e){for(var n,r=[],o=function(e){var e=e,n=987654321,r=4294967295;return function(){n=36969*(65535&n)+(n>>16)&r,e=18e3*(65535&e)+(e>>16)&r;var o=(n<<16)+e&r;return o/=4294967296,o+=.5,o*(t.random()>.5?1:-1)}},a=0;e>a;a+=4){var s=o(4294967296*(n||t.random()));n=987654071*s(),r.push(4294967296*s()|0)}return new i.init(r,e)}}),a=n.enc={},s=a.Hex={stringify:function(t){for(var e=t.words,n=t.sigBytes,r=[],o=0;n>o;o++){var i=e[o>>>2]>>>24-o%4*8&255;r.push((i>>>4).toString(16)),r.push((15&i).toString(16))}return r.join("")},parse:function(t){for(var e=t.length,n=[],r=0;e>r;r+=2)n[r>>>3]|=parseInt(t.substr(r,2),16)<<24-r%8*4;return new i.init(n,e/2)}},u=a.Latin1={stringify:function(t){for(var e=t.words,n=t.sigBytes,r=[],o=0;n>o;o++){var i=e[o>>>2]>>>24-o%4*8&255;r.push(String.fromCharCode(i))}return r.join("")},parse:function(t){for(var e=t.length,n=[],r=0;e>r;r++)n[r>>>2]|=(255&t.charCodeAt(r))<<24-r%4*8;return new i.init(n,e)}},c=a.Utf8={stringify:function(t){try{return decodeURIComponent(escape(u.stringify(t)))}catch(e){throw new Error("Malformed UTF-8 data")}},parse:function(t){return u.parse(unescape(encodeURIComponent(t)))}},l=r.BufferedBlockAlgorithm=o.extend({reset:function(){this._data=new i.init,this._nDataBytes=0},_append:function(t){"string"==typeof t&&(t=c.parse(t)),this._data.concat(t),this._nDataBytes+=t.sigBytes},_process:function(e){var n=this._data,r=n.words,o=n.sigBytes,a=this.blockSize,s=4*a,u=o/s;u=e?t.ceil(u):t.max((0|u)-this._minBufferSize,0);var c=u*a,l=t.min(4*c,o);if(c){for(var p=0;c>p;p+=a)this._doProcessBlock(r,p);var f=r.splice(0,c);n.sigBytes-=l}return new i.init(f,l)},clone:function(){var t=o.clone.call(this);return t._data=this._data.clone(),t},_minBufferSize:0}),p=(r.Hasher=l.extend({cfg:o.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 p.HMAC.init(t,n).finalize(e)}}}),n.algo={});return n}(Math);return t})},{}],33:[function(t,e,n){!function(r,o,i){"object"==typeof n?e.exports=n=o(t("./core"),t("./x64-core")):"function"==typeof define&&define.amd?define(["./core","./x64-core"],o):o(r.CryptoJS)}(this,function(t){return function(e){var n=t,r=n.lib,o=r.WordArray,i=r.Hasher,a=n.x64,s=a.Word,u=n.algo,c=[],l=[],p=[];!function(){for(var t=1,e=0,n=0;24>n;n++){c[t+5*e]=(n+1)*(n+2)/2%64;var r=e%5,o=(2*t+3*e)%5;t=r,e=o}for(var t=0;5>t;t++)for(var e=0;5>e;e++)l[t+5*e]=e+(2*t+3*e)%5*5;for(var i=1,a=0;24>a;a++){for(var u=0,f=0,m=0;7>m;m++){if(1&i){var h=(1<h?f^=1<t;t++)f[t]=s.create()}();var m=u.SHA3=i.extend({cfg:i.cfg.extend({outputLength:512}),_doReset:function(){for(var t=this._state=[],e=0;25>e;e++)t[e]=new s.init;this.blockSize=(1600-2*this.cfg.outputLength)/32},_doProcessBlock:function(t,e){for(var n=this._state,r=this.blockSize/2,o=0;r>o;o++){var i=t[e+2*o],a=t[e+2*o+1];i=16711935&(i<<8|i>>>24)|4278255360&(i<<24|i>>>8),a=16711935&(a<<8|a>>>24)|4278255360&(a<<24|a>>>8);var s=n[o];s.high^=a,s.low^=i}for(var u=0;24>u;u++){for(var m=0;5>m;m++){for(var h=0,d=0,y=0;5>y;y++){var s=n[m+5*y];h^=s.high,d^=s.low}var g=f[m];g.high=h,g.low=d}for(var m=0;5>m;m++)for(var v=f[(m+4)%5],b=f[(m+1)%5],w=b.high,_=b.low,h=v.high^(w<<1|_>>>31),d=v.low^(_<<1|w>>>31),y=0;5>y;y++){var s=n[m+5*y];s.high^=h,s.low^=d}for(var x=1;25>x;x++){var s=n[x],F=s.high,B=s.low,I=c[x];if(32>I)var h=F<>>32-I,d=B<>>32-I;else var h=B<>>64-I,d=F<>>64-I;var k=f[l[x]];k.high=h,k.low=d}var N=f[0],P=n[0];N.high=P.high,N.low=P.low;for(var m=0;5>m;m++)for(var y=0;5>y;y++){var x=m+5*y,s=n[x],A=f[x],O=f[(m+1)%5+5*y],T=f[(m+2)%5+5*y];s.high=A.high^~O.high&T.high,s.low=A.low^~O.low&T.low}var s=n[0],D=p[u];s.high^=D.high,s.low^=D.low}},_doFinalize:function(){var t=this._data,n=t.words,r=(8*this._nDataBytes,8*t.sigBytes),i=32*this.blockSize;n[r>>>5]|=1<<24-r%32,n[(e.ceil((r+1)/i)*i>>>5)-1]|=128,t.sigBytes=4*n.length,this._process();for(var a=this._state,s=this.cfg.outputLength/8,u=s/8,c=[],l=0;u>l;l++){var p=a[l],f=p.high,m=p.low;f=16711935&(f<<8|f>>>24)|4278255360&(f<<24|f>>>8),m=16711935&(m<<8|m>>>24)|4278255360&(m<<24|m>>>8),c.push(m),c.push(f)}return new o.init(c,s)},clone:function(){for(var t=i.clone.call(this),e=t._state=this._state.slice(0),n=0;25>n;n++)e[n]=e[n].clone();return t}});n.SHA3=i._createHelper(m),n.HmacSHA3=i._createHmacHelper(m)}(Math),t.SHA3})},{"./core":32,"./x64-core":34}],34:[function(t,e,n){!function(r,o){"object"==typeof n?e.exports=n=o(t("./core")):"function"==typeof define&&define.amd?define(["./core"],o):o(r.CryptoJS)}(this,function(t){return function(e){{var n=t,r=n.lib,o=r.Base,i=r.WordArray,a=n.x64={};a.Word=o.extend({init:function(t,e){this.high=t,this.low=e}}),a.WordArray=o.extend({init:function(t,n){t=this.words=t||[],this.sigBytes=n!=e?n:8*t.length},toX32:function(){for(var t=this.words,e=t.length,n=[],r=0;e>r;r++){var o=t[r];n.push(o.high),n.push(o.low)}return i.create(n,this.sigBytes)},clone:function(){for(var t=o.clone.call(this),e=t.words=this.words.slice(0),n=e.length,r=0;n>r;r++)e[r]=e[r].clone();return t}})}}(),t})},{"./core":32}],"bignumber.js":[function(t,e,n){"use strict";e.exports=BigNumber},{}],web3:[function(t,e,n){var r=t("./lib/web3");r.providers.HttpProvider=t("./lib/web3/httpprovider"),r.providers.QtSyncProvider=t("./lib/web3/qtsync"),r.eth.contract=t("./lib/web3/contract"),r.eth.namereg=t("./lib/web3/namereg"),r.eth.sendIBANTransaction=t("./lib/web3/transfer"),"undefined"!=typeof window&&"undefined"==typeof window.web3&&(window.web3=r),e.exports=r},{"./lib/web3":9,"./lib/web3/contract":11,"./lib/web3/httpprovider":19,"./lib/web3/namereg":23,"./lib/web3/qtsync":26,"./lib/web3/transfer":29}]},{},["web3"]); \ No newline at end of file diff --git a/libjsqrc/ethereumjs/dist/web3.js b/libjsqrc/ethereumjs/dist/web3.js index ec5cdfe83..70b096cf1 100644 --- a/libjsqrc/ethereumjs/dist/web3.js +++ b/libjsqrc/ethereumjs/dist/web3.js @@ -799,7 +799,7 @@ module.exports = { ETH_SIGNATURE_LENGTH: 4, ETH_UNITS: ETH_UNITS, ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }, - ETH_POLLING_TIMEOUT: 1000, + ETH_POLLING_TIMEOUT: 1000/2, defaultBlock: 'latest', defaultAccount: undefined }; @@ -1348,7 +1348,7 @@ module.exports = { },{"bignumber.js":"bignumber.js"}],8:[function(require,module,exports){ module.exports={ - "version": "0.5.0" + "version": "0.6.0" } },{}],9:[function(require,module,exports){ @@ -1388,7 +1388,6 @@ var Filter = require('./web3/filter'); var utils = require('./utils/utils'); var formatters = require('./web3/formatters'); var RequestManager = require('./web3/requestmanager'); -var Method = require('./web3/method'); var c = require('./utils/config'); var Property = require('./web3/property'); var Batch = require('./web3/batch'); @@ -1448,8 +1447,7 @@ web3.eth.filter = function (fil, eventParams, options, formatter) { return fil(eventParams, options); } - // what outputLogFormatter? that's wrong - //return new Filter(fil, watches.eth(), formatters.outputLogFormatter); + // output logs works for blockFilter and pendingTransaction filters? return new Filter(fil, watches.eth(), formatter || formatters.outputLogFormatter); }; /*jshint maxparams:3 */ @@ -1504,6 +1502,23 @@ Object.defineProperty(web3.eth, 'defaultAccount', { } }); + +// EXTEND +web3._extend = function(extension){ + /*jshint maxcomplexity: 6 */ + + if(extension.property && !web3[extension.property]) + web3[extension.property] = {}; + + setupMethods(web3[extension.property] || web3, extension.methods || []); + setupProperties(web3[extension.property] || web3, extension.properties || []); +}; +web3._extend.formatters = formatters; +web3._extend.utils = utils; +web3._extend.Method = require('./web3/method'); +web3._extend.Property = require('./web3/property'); + + /// setups all api methods setupProperties(web3, web3Properties); setupMethods(web3.net, net.methods); @@ -1513,18 +1528,6 @@ 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; @@ -1951,11 +1954,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({ @@ -2034,6 +2037,13 @@ var getTransactionCount = new Method({ outputFormatter: utils.toDecimal }); +var sendRawTransaction = new Method({ + name: 'sendRawTransaction', + call: 'eth_sendRawTransaction', + params: 1, + inputFormatter: [] +}); + var sendTransaction = new Method({ name: 'sendTransaction', call: 'eth_sendTransaction', @@ -2100,6 +2110,7 @@ var methods = [ getTransactionCount, call, estimateGas, + sendRawTransaction, sendTransaction, compileSolidity, compileLLL, @@ -2422,21 +2433,36 @@ var getOptions = function (options) { }; }; -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); +/** +Adds the callback and sets up the methods, to iterate over the results. + +@method getLogsAtStart +@param {Object} self +@param {funciton} +*/ +var getLogsAtStart = function(self, callback){ + // call getFilterLogs for the first watch callback start + if (!utils.isString(self.options)) { + self.get(function (err, messages) { + // don't send all the responses to all the watches again... just to self one + if (err) { + callback(err); + } + + messages.forEach(function (message) { + callback(null, message); + }); + }); + } }; -Filter.prototype.watch = function (callback) { - this.callbacks.push(callback); - var self = this; +/** +Adds the callback and sets up the methods, to iterate over the results. + +@method pollFilter +@param {Object} self +*/ +var pollFilter = function(self) { var onMessage = function (error, messages) { if (error) { @@ -2453,29 +2479,55 @@ Filter.prototype.watch = function (callback) { }); }; - // 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); - } + RequestManager.getInstance().startPolling({ + method: self.implementation.poll.call, + params: [self.filterId], + }, self.filterId, onMessage, self.stopWatching.bind(self)); - messages.forEach(function (message) { - callback(null, message); +}; + +var Filter = function (options, methods, formatter) { + var self = this; + var implementation = {}; + methods.forEach(function (method) { + method.attachToObject(implementation); + }); + this.options = getOptions(options); + this.implementation = implementation; + this.callbacks = []; + this.pollFilters = []; + this.formatter = formatter; + this.implementation.newFilter(this.options, function(error, id){ + if(error) { + self.callbacks.forEach(function(callback){ + callback(error); }); - }); + } else { + self.filterId = id; + // get filter logs at start + self.callbacks.forEach(function(callback){ + getLogsAtStart(self, callback); + }); + pollFilter(self); + } + }); +}; + +Filter.prototype.watch = function (callback) { + this.callbacks.push(callback); + + if(this.filterId) { + getLogsAtStart(this, callback); + pollFilter(this); } - RequestManager.getInstance().startPolling({ - method: this.implementation.poll.call, - params: [this.filterId], - }, this.filterId, onMessage, this.stopWatching.bind(this)); + return this; }; Filter.prototype.stopWatching = function () { RequestManager.getInstance().stopPolling(this.filterId); - this.implementation.uninstallFilter(this.filterId); + // remove filter async + this.implementation.uninstallFilter(this.filterId, function(){}); this.callbacks = []; }; @@ -2497,6 +2549,8 @@ Filter.prototype.get = function (callback) { return self.formatter ? self.formatter(log) : log; }); } + + return this; }; module.exports = Filter; @@ -2594,8 +2648,10 @@ var inputTransactionFormatter = function (options){ * @returns {Object} transaction */ var outputTransactionFormatter = function (tx){ - tx.blockNumber = utils.toDecimal(tx.blockNumber); - tx.transactionIndex = utils.toDecimal(tx.transactionIndex); + if(tx.blockNumber !== null) + tx.blockNumber = utils.toDecimal(tx.blockNumber); + if(tx.transactionIndex !== null) + tx.transactionIndex = utils.toDecimal(tx.transactionIndex); tx.nonce = utils.toDecimal(tx.nonce); tx.gas = utils.toDecimal(tx.gas); tx.gasPrice = utils.toBigNumber(tx.gasPrice); @@ -2617,7 +2673,8 @@ var outputBlockFormatter = function(block) { block.gasUsed = utils.toDecimal(block.gasUsed); block.size = utils.toDecimal(block.size); block.timestamp = utils.toDecimal(block.timestamp); - block.number = utils.toDecimal(block.number); + if(block.number !== null) + block.number = utils.toDecimal(block.number); block.difficulty = utils.toBigNumber(block.difficulty); block.totalDifficulty = utils.toBigNumber(block.totalDifficulty); @@ -2640,13 +2697,12 @@ var outputBlockFormatter = function(block) { * @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); + if(log.blockNumber !== null) + log.blockNumber = utils.toDecimal(log.blockNumber); + if(log.transactionIndex !== null) + log.transactionIndex = utils.toDecimal(log.transactionIndex); + if(log.logIndex !== null) + log.logIndex = utils.toDecimal(log.logIndex); return log; }; @@ -2748,6 +2804,7 @@ module.exports = { var web3 = require('../web3'); var coder = require('../solidity/coder'); var utils = require('../utils/utils'); +var formatters = require('./formatters'); var sha3 = require('../utils/sha3'); /** @@ -2771,6 +2828,12 @@ SolidityFunction.prototype.extractCallback = function (args) { } }; +SolidityFunction.prototype.extractDefaultBlock = function (args) { + if (args.length > this._inputTypes.length && !utils.isObject(args[args.length -1])) { + return formatters.inputDefaultBlockNumberFormatter(args.pop()); // modify the args array! + } +}; + /** * Should be used to create payload from arguments * @@ -2822,15 +2885,17 @@ SolidityFunction.prototype.unpackOutput = function (output) { SolidityFunction.prototype.call = function () { var args = Array.prototype.slice.call(arguments).filter(function (a) {return a !== undefined; }); var callback = this.extractCallback(args); + var defaultBlock = this.extractDefaultBlock(args); var payload = this.toPayload(args); + if (!callback) { - var output = web3.eth.call(payload); + var output = web3.eth.call(payload, defaultBlock); return this.unpackOutput(output); } var self = this; - web3.eth.call(payload, function (error, output) { + web3.eth.call(payload, defaultBlock, function (error, output) { callback(error, self.unpackOutput(output)); }); }; @@ -2949,7 +3014,7 @@ SolidityFunction.prototype.attachToContract = function (contract) { module.exports = SolidityFunction; -},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9}],19:[function(require,module,exports){ +},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9,"./formatters":17}],19:[function(require,module,exports){ /* This file is part of ethereum.js. @@ -2987,6 +3052,7 @@ HttpProvider.prototype.send = function (payload) { var request = new XMLHttpRequest(); request.open('POST', this.host, false); + request.setRequestHeader('Content-type','application/json'); try { request.send(JSON.stringify(payload)); @@ -3030,7 +3096,8 @@ HttpProvider.prototype.sendAsync = function (payload, callback) { }; request.open('POST', this.host, true); - + request.setRequestHeader('Content-type','application/json'); + try { request.send(JSON.stringify(payload)); } catch(error) { @@ -3715,9 +3782,9 @@ var RequestManager = function (provider) { arguments.callee._singletonInstance = this; this.provider = provider; - this.polls = []; + this.polls = {}; this.timeout = null; - this.poll(); + this.isPolling = false; }; /** @@ -3812,6 +3879,11 @@ RequestManager.prototype.sendBatch = function (data, callback) { */ RequestManager.prototype.setProvider = function (p) { this.provider = p; + + if (this.provider && !this.isPolling) { + this.poll(); + this.isPolling = true; + } }; /*jshint maxparams:4 */ @@ -3828,7 +3900,7 @@ RequestManager.prototype.setProvider = function (p) { * @todo cleanup number of params */ RequestManager.prototype.startPolling = function (data, pollId, callback, uninstall) { - this.polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall}); + this.polls['poll_'+ pollId] = {data: data, id: pollId, callback: callback, uninstall: uninstall}; }; /*jshint maxparams:3 */ @@ -3839,24 +3911,19 @@ RequestManager.prototype.startPolling = function (data, pollId, callback, uninst * @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); - } - } + delete this.polls['poll_'+ pollId]; }; /** - * Should be called to reset polling mechanism of request manager + * Should be called to reset the polling mechanism of the request manager * * @method reset */ RequestManager.prototype.reset = function () { - this.polls.forEach(function (poll) { - poll.uninstall(poll.id); - }); - this.polls = []; + for (var key in this.polls) { + this.polls[key].uninstall(); + } + this.polls = {}; if (this.timeout) { clearTimeout(this.timeout); @@ -3871,9 +3938,10 @@ RequestManager.prototype.reset = function () { * @method poll */ RequestManager.prototype.poll = function () { + /*jshint maxcomplexity: 6 */ this.timeout = setTimeout(this.poll.bind(this), c.ETH_POLLING_TIMEOUT); - if (!this.polls.length) { + if (Object.keys(this.polls).length === 0) { return; } @@ -3882,9 +3950,18 @@ RequestManager.prototype.poll = function () { return; } - var payload = Jsonrpc.getInstance().toBatchPayload(this.polls.map(function (data) { - return data.data; - })); + var pollsData = []; + var pollsKeys = []; + for (var key in this.polls) { + pollsData.push(this.polls[key].data); + pollsKeys.push(key); + } + + if (pollsData.length === 0) { + return; + } + + var payload = Jsonrpc.getInstance().toBatchPayload(pollsData); var self = this; this.provider.sendAsync(payload, function (error, results) { @@ -3892,14 +3969,21 @@ RequestManager.prototype.poll = function () { if (error) { return; } - + if (!utils.isArray(results)) { throw errors.InvalidResponse(results); } results.map(function (result, index) { - result.callback = self.polls[index].callback; - return result; + var key = pollsKeys[index]; + // make sure the filter is still installed after arrival of the request + if (self.polls[key]) { + result.callback = self.polls[key].callback; + return result; + } else + return false; + }).filter(function (result) { + return !!result; }).filter(function (result) { var valid = Jsonrpc.getInstance().isValidResponse(result); if (!valid) { @@ -4115,11 +4199,11 @@ var eth = function () { switch(type) { case 'latest': - args.pop(); + args.shift(); this.params = 0; return 'eth_newBlockFilter'; case 'pending': - args.pop(); + args.shift(); this.params = 0; return 'eth_newPendingTransactionFilter'; default: @@ -8275,4 +8359,4 @@ module.exports = web3; },{"./lib/web3":9,"./lib/web3/contract":11,"./lib/web3/httpprovider":19,"./lib/web3/namereg":23,"./lib/web3/qtsync":26,"./lib/web3/transfer":29}]},{},["web3"]) -//# sourceMappingURL=data:application/json;charset:utf-8;base64,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 +//# sourceMappingURL=web3.js.map diff --git a/libjsqrc/ethereumjs/dist/web3.js.map b/libjsqrc/ethereumjs/dist/web3.js.map new file mode 100644 index 000000000..b000cdd4b --- /dev/null +++ b/libjsqrc/ethereumjs/dist/web3.js.map @@ -0,0 +1,85 @@ +{ + "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/sha3.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/icap.js", + "lib/web3/jsonrpc.js", + "lib/web3/method.js", + "lib/web3/namereg.js", + "lib/web3/net.js", + "lib/web3/property.js", + "lib/web3/qtsync.js", + "lib/web3/requestmanager.js", + "lib/web3/shh.js", + "lib/web3/transfer.js", + "lib/web3/watches.js", + "node_modules/browserify/lib/_empty.js", + "node_modules/crypto-js/core.js", + "node_modules/crypto-js/sha3.js", + "node_modules/crypto-js/x64-core.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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC9EA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClfA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC3RA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACnMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACtMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC1OA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC5GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;AC9CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;ACvQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;AC9FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;;ACruBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AClUA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AC/SA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;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;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 || this.offset !== undefined;\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), 0);\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), 0);\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 'femtoether',\n 'picoether',\n 'nanoether',\n 'microether',\n 'milliether',\n 'nano',\n 'micro',\n 'milli',\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/2,\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 sha3.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar utils = require('./utils');\nvar sha3 = require('crypto-js/sha3');\n\nmodule.exports = function (str, isNew) {\n if (str.substr(0, 2) === '0x' && !isNew) {\n console.warn('requirement of using web3.fromAscii before sha3 is deprecated');\n console.warn('new usage: \\'web3.sha3(\"hello\")\\'');\n console.warn('see https://github.com/ethereum/web3.js/pull/205');\n console.warn('if you need to hash hex value, you can do \\'sha3(\"0xfff\", true)\\'');\n str = utils.toAscii(str);\n }\n\n return sha3(str, {\n outputLength: 256\n }).toString();\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 'femtoether': '1000',\n 'mwei': '1000000',\n 'babbage': '1000000',\n 'picoether': '1000000',\n 'gwei': '1000000000',\n 'shannon': '1000000000',\n 'nanoether': '1000000000',\n 'nano': '1000000000',\n 'szabo': '1000000000000',\n 'microether': '1000000000000',\n 'micro': '1000000000000',\n 'finney': '1000000000000000',\n 'milliether': '1000000000000000',\n 'milli': '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 * SI Short SI Full Effigy Other\n * - kwei femtoether ada\n * - mwei picoether babbage\n * - gwei nanoether shannon nano\n * - -- microether szabo micro\n * - -- milliether finney milli\n * - ether -- --\n * - kether einstein grand \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 * SI Short SI Full Effigy Other\n * - kwei femtoether ada\n * - mwei picoether babbage \n * - gwei nanoether shannon nano\n * - -- microether szabo micro\n * - -- milliether finney milli\n * - ether -- --\n * - kether einstein grand \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\n/**\n * This method should be called to check if string is valid ethereum IBAN number\n * Supports direct and indirect IBANs\n *\n * @method isIBAN\n * @param {String}\n * @return {Boolean}\n */\nvar isIBAN = function (iban) {\n return /^XE[0-9]{2}(ETH[0-9A-Z]{13}|[0-9A-Z]{30})$/.test(iban);\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 isIBAN: isIBAN\n};\n\n", + "module.exports={\n \"version\": \"0.6.0\"\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 Property = require('./web3/property');\nvar Batch = require('./web3/batch');\nvar sha3 = require('./utils/sha3');\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 // output logs works for blockFilter and pendingTransaction filters?\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.isIBAN = utils.isIBAN;\nweb3.sha3 = sha3;\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\n// EXTEND\nweb3._extend = function(extension){\n /*jshint maxcomplexity: 6 */\n\n if(extension.property && !web3[extension.property])\n web3[extension.property] = {};\n\n setupMethods(web3[extension.property] || web3, extension.methods || []);\n setupProperties(web3[extension.property] || web3, extension.properties || []);\n};\nweb3._extend.formatters = formatters;\nweb3._extend.utils = utils;\nweb3._extend.Method = require('./web3/method');\nweb3._extend.Property = require('./web3/property');\n\n\n/// setups all api methods\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 sendRawTransaction = new Method({\n name: 'sendRawTransaction',\n call: 'eth_sendRawTransaction',\n params: 1,\n inputFormatter: []\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 sendRawTransaction,\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');\nvar sha3 = require('../utils/sha3');\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 sha3(this._name);\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\n/**\nAdds the callback and sets up the methods, to iterate over the results.\n\n@method getLogsAtStart\n@param {Object} self\n@param {funciton} \n*/\nvar getLogsAtStart = function(self, callback){\n // call getFilterLogs for the first watch callback start\n if (!utils.isString(self.options)) {\n self.get(function (err, messages) {\n // don't send all the responses to all the watches again... just to self one\n if (err) {\n callback(err);\n }\n\n messages.forEach(function (message) {\n callback(null, message);\n });\n });\n }\n};\n\n/**\nAdds the callback and sets up the methods, to iterate over the results.\n\n@method pollFilter\n@param {Object} self\n*/\nvar pollFilter = function(self) {\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 RequestManager.getInstance().startPolling({\n method: self.implementation.poll.call,\n params: [self.filterId],\n }, self.filterId, onMessage, self.stopWatching.bind(self));\n\n};\n\nvar Filter = function (options, methods, formatter) {\n var self = this;\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.pollFilters = [];\n this.formatter = formatter;\n this.implementation.newFilter(this.options, function(error, id){\n if(error) {\n self.callbacks.forEach(function(callback){\n callback(error);\n });\n } else {\n self.filterId = id;\n // get filter logs at start\n self.callbacks.forEach(function(callback){\n getLogsAtStart(self, callback);\n });\n pollFilter(self);\n }\n });\n};\n\nFilter.prototype.watch = function (callback) {\n this.callbacks.push(callback);\n\n if(this.filterId) {\n getLogsAtStart(this, callback);\n pollFilter(this);\n }\n\n return this;\n};\n\nFilter.prototype.stopWatching = function () {\n RequestManager.getInstance().stopPolling(this.filterId);\n // remove filter async\n this.implementation.uninstallFilter(this.filterId, function(){});\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 return this;\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 if(tx.blockNumber !== null)\n tx.blockNumber = utils.toDecimal(tx.blockNumber);\n if(tx.transactionIndex !== null)\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 if(block.number !== null)\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.blockNumber !== null)\n log.blockNumber = utils.toDecimal(log.blockNumber);\n if(log.transactionIndex !== null)\n log.transactionIndex = utils.toDecimal(log.transactionIndex);\n if(log.logIndex !== null)\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');\nvar formatters = require('./formatters');\nvar sha3 = require('../utils/sha3');\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\nSolidityFunction.prototype.extractDefaultBlock = function (args) {\n if (args.length > this._inputTypes.length && !utils.isObject(args[args.length -1])) {\n return formatters.inputDefaultBlockNumberFormatter(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 sha3(this._name).slice(0, 8);\n};\n\n\nSolidityFunction.prototype.unpackOutput = function (output) {\n if (!output) {\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).filter(function (a) {return a !== undefined; });\n var callback = this.extractCallback(args);\n var defaultBlock = this.extractDefaultBlock(args);\n var payload = this.toPayload(args);\n\n\n if (!callback) {\n var output = web3.eth.call(payload, defaultBlock);\n return this.unpackOutput(output);\n } \n \n var self = this;\n web3.eth.call(payload, defaultBlock, 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).filter(function (a) {return a !== undefined; });\n var callback = this.extractCallback(args);\n var payload = this.toPayload(args);\n\n if (!callback) {\n return web3.eth.sendTransaction(payload);\n }\n\n web3.eth.sendTransaction(payload, callback);\n};\n\n/**\n * Should be used to estimateGas of solidity function\n *\n * @method estimateGas\n * @param {Object} options\n */\nSolidityFunction.prototype.estimateGas = 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 return web3.eth.estimateGas(payload);\n }\n\n web3.eth.estimateGas(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 execute.estimateGas = this.estimateGas.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 request.setRequestHeader('Content-type','application/json');\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 request.setRequestHeader('Content-type','application/json');\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/** \n * @file icap.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar utils = require('../utils/utils');\n\n/**\n * This prototype should be used to extract necessary information from iban address\n *\n * @param {String} iban\n */\nvar ICAP = function (iban) {\n this._iban = iban;\n};\n\n/**\n * Should be called to check if icap is correct\n *\n * @method isValid\n * @returns {Boolean} true if it is, otherwise false\n */\nICAP.prototype.isValid = function () {\n return utils.isIBAN(this._iban);\n};\n\n/**\n * Should be called to check if iban number is direct\n *\n * @method isDirect\n * @returns {Boolean} true if it is, otherwise false\n */\nICAP.prototype.isDirect = function () {\n return this._iban.length === 34;\n};\n\n/**\n * Should be called to check if iban number if indirect\n *\n * @method isIndirect\n * @returns {Boolean} true if it is, otherwise false\n */\nICAP.prototype.isIndirect = function () {\n return this._iban.length === 20;\n};\n\n/**\n * Should be called to get iban checksum\n * Uses the mod-97-10 checksumming protocol (ISO/IEC 7064:2003)\n *\n * @method checksum\n * @returns {String} checksum\n */\nICAP.prototype.checksum = function () {\n return this._iban.substr(2, 2);\n};\n\n/**\n * Should be called to get institution identifier\n * eg. XREG\n *\n * @method institution\n * @returns {String} institution identifier\n */\nICAP.prototype.institution = function () {\n return this.isIndirect() ? this._iban.substr(7, 4) : '';\n};\n\n/**\n * Should be called to get client identifier within institution\n * eg. GAVOFYORK\n *\n * @method client\n * @returns {String} client identifier\n */\nICAP.prototype.client = function () {\n return this.isIndirect() ? this._iban.substr(11) : '';\n};\n\n/**\n * Should be called to get client direct address\n *\n * @method address\n * @returns {String} client direct address\n */\nICAP.prototype.address = function () {\n return this.isDirect() ? this._iban.substr(4) : '';\n};\n\nmodule.exports = ICAP;\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/** \n * @file namereg.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar contract = require('./contract');\n\nvar address = '0xc6d9d2cd449a754c494264e1809c50e34d64562b';\n\nvar abi = [\n {\"constant\":true,\"inputs\":[{\"name\":\"_owner\",\"type\":\"address\"}],\"name\":\"name\",\"outputs\":[{\"name\":\"o_name\",\"type\":\"bytes32\"}],\"type\":\"function\"},\n {\"constant\":true,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"}],\"name\":\"owner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"type\":\"function\"},\n {\"constant\":true,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"}],\"name\":\"content\",\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\"}],\"type\":\"function\"},\n {\"constant\":true,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"}],\"name\":\"addr\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"type\":\"function\"},\n {\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"}],\"name\":\"reserve\",\"outputs\":[],\"type\":\"function\"},\n {\"constant\":true,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"}],\"name\":\"subRegistrar\",\"outputs\":[{\"name\":\"o_subRegistrar\",\"type\":\"address\"}],\"type\":\"function\"},\n {\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"},{\"name\":\"_newOwner\",\"type\":\"address\"}],\"name\":\"transfer\",\"outputs\":[],\"type\":\"function\"},\n {\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"},{\"name\":\"_registrar\",\"type\":\"address\"}],\"name\":\"setSubRegistrar\",\"outputs\":[],\"type\":\"function\"},\n {\"constant\":false,\"inputs\":[],\"name\":\"Registrar\",\"outputs\":[],\"type\":\"function\"},\n {\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"},{\"name\":\"_a\",\"type\":\"address\"},{\"name\":\"_primary\",\"type\":\"bool\"}],\"name\":\"setAddress\",\"outputs\":[],\"type\":\"function\"},\n {\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"},{\"name\":\"_content\",\"type\":\"bytes32\"}],\"name\":\"setContent\",\"outputs\":[],\"type\":\"function\"},\n {\"constant\":false,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"}],\"name\":\"disown\",\"outputs\":[],\"type\":\"function\"},\n {\"constant\":true,\"inputs\":[{\"name\":\"_name\",\"type\":\"bytes32\"}],\"name\":\"register\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"type\":\"function\"},\n {\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"name\",\"type\":\"bytes32\"}],\"name\":\"Changed\",\"type\":\"event\"},\n {\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"name\",\"type\":\"bytes32\"},{\"indexed\":true,\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"PrimaryChanged\",\"type\":\"event\"}\n];\n\nmodule.exports = contract(abi).at(address);\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.isPolling = false;\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 if (this.provider && !this.isPolling) {\n this.poll();\n this.isPolling = true;\n }\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['poll_'+ pollId] = {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 delete this.polls['poll_'+ pollId];\n};\n\n/**\n * Should be called to reset the polling mechanism of the request manager\n *\n * @method reset\n */\nRequestManager.prototype.reset = function () {\n for (var key in this.polls) {\n this.polls[key].uninstall();\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 /*jshint maxcomplexity: 6 */\n this.timeout = setTimeout(this.poll.bind(this), c.ETH_POLLING_TIMEOUT);\n\n if (Object.keys(this.polls).length === 0) {\n return;\n }\n\n if (!this.provider) {\n console.error(errors.InvalidProvider());\n return;\n }\n\n var pollsData = [];\n var pollsKeys = [];\n for (var key in this.polls) {\n pollsData.push(this.polls[key].data);\n pollsKeys.push(key);\n }\n\n if (pollsData.length === 0) {\n return;\n }\n\n var payload = Jsonrpc.getInstance().toBatchPayload(pollsData);\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 var key = pollsKeys[index];\n // make sure the filter is still installed after arrival of the request\n if (self.polls[key]) {\n result.callback = self.polls[key].callback;\n return result;\n } else\n return false;\n }).filter(function (result) {\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/** \n * @file transfer.js\n * @author Marek Kotewicz \n * @date 2015\n */\n\nvar web3 = require('../web3');\nvar ICAP = require('./icap');\nvar namereg = require('./namereg');\nvar contract = require('./contract');\n\n/**\n * Should be used to make ICAP transfer\n *\n * @method transfer\n * @param {String} iban number\n * @param {String} from (address)\n * @param {Value} value to be tranfered\n * @param {Function} callback, callback\n */\nvar transfer = function (from, iban, value, callback) {\n var icap = new ICAP(iban); \n if (!icap.isValid()) {\n throw new Error('invalid iban address');\n }\n\n if (icap.isDirect()) {\n return transferToAddress(from, icap.address(), value, callback);\n }\n \n if (!callback) {\n var address = namereg.addr(icap.institution());\n return deposit(from, address, value, icap.client());\n }\n\n namereg.addr(icap.insitution(), function (err, address) {\n return deposit(from, address, value, icap.client(), callback);\n });\n \n};\n\n/**\n * Should be used to transfer funds to certain address\n *\n * @method transferToAddress\n * @param {String} address\n * @param {String} from (address)\n * @param {Value} value to be tranfered\n * @param {Function} callback, callback\n */\nvar transferToAddress = function (from, address, value, callback) {\n return web3.eth.sendTransaction({\n address: address,\n from: from,\n value: value\n }, callback);\n};\n\n/**\n * Should be used to deposit funds to generic Exchange contract (must implement deposit(bytes32) method!)\n *\n * @method deposit\n * @param {String} address\n * @param {String} from (address)\n * @param {Value} value to be tranfered\n * @param {String} client unique identifier\n * @param {Function} callback, callback\n */\nvar deposit = function (from, address, value, client, callback) {\n var abi = [{\"constant\":false,\"inputs\":[{\"name\":\"name\",\"type\":\"bytes32\"}],\"name\":\"deposit\",\"outputs\":[],\"type\":\"function\"}];\n return contract(abi).at(address).deposit(client, {\n from: from,\n value: value\n }, callback);\n};\n\nmodule.exports = transfer;\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.shift();\n this.params = 0;\n return 'eth_newBlockFilter';\n case 'pending':\n args.shift();\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, + ";(function (root, factory) {\n\tif (typeof exports === \"object\") {\n\t\t// CommonJS\n\t\tmodule.exports = exports = factory();\n\t}\n\telse if (typeof define === \"function\" && define.amd) {\n\t\t// AMD\n\t\tdefine([], factory);\n\t}\n\telse {\n\t\t// Global (browser)\n\t\troot.CryptoJS = factory();\n\t}\n}(this, function () {\n\n\t/**\n\t * CryptoJS core components.\n\t */\n\tvar CryptoJS = CryptoJS || (function (Math, undefined) {\n\t /**\n\t * CryptoJS namespace.\n\t */\n\t var C = {};\n\n\t /**\n\t * Library namespace.\n\t */\n\t var C_lib = C.lib = {};\n\n\t /**\n\t * Base object for prototypal inheritance.\n\t */\n\t var Base = C_lib.Base = (function () {\n\t function F() {}\n\n\t return {\n\t /**\n\t * Creates a new object that inherits from this object.\n\t *\n\t * @param {Object} overrides Properties to copy into the new object.\n\t *\n\t * @return {Object} The new object.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var MyType = CryptoJS.lib.Base.extend({\n\t * field: 'value',\n\t *\n\t * method: function () {\n\t * }\n\t * });\n\t */\n\t extend: function (overrides) {\n\t // Spawn\n\t F.prototype = this;\n\t var subtype = new F();\n\n\t // Augment\n\t if (overrides) {\n\t subtype.mixIn(overrides);\n\t }\n\n\t // Create default initializer\n\t if (!subtype.hasOwnProperty('init')) {\n\t subtype.init = function () {\n\t subtype.$super.init.apply(this, arguments);\n\t };\n\t }\n\n\t // Initializer's prototype is the subtype object\n\t subtype.init.prototype = subtype;\n\n\t // Reference supertype\n\t subtype.$super = this;\n\n\t return subtype;\n\t },\n\n\t /**\n\t * Extends this object and runs the init method.\n\t * Arguments to create() will be passed to init().\n\t *\n\t * @return {Object} The new object.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var instance = MyType.create();\n\t */\n\t create: function () {\n\t var instance = this.extend();\n\t instance.init.apply(instance, arguments);\n\n\t return instance;\n\t },\n\n\t /**\n\t * Initializes a newly created object.\n\t * Override this method to add some logic when your objects are created.\n\t *\n\t * @example\n\t *\n\t * var MyType = CryptoJS.lib.Base.extend({\n\t * init: function () {\n\t * // ...\n\t * }\n\t * });\n\t */\n\t init: function () {\n\t },\n\n\t /**\n\t * Copies properties into this object.\n\t *\n\t * @param {Object} properties The properties to mix in.\n\t *\n\t * @example\n\t *\n\t * MyType.mixIn({\n\t * field: 'value'\n\t * });\n\t */\n\t mixIn: function (properties) {\n\t for (var propertyName in properties) {\n\t if (properties.hasOwnProperty(propertyName)) {\n\t this[propertyName] = properties[propertyName];\n\t }\n\t }\n\n\t // IE won't copy toString using the loop above\n\t if (properties.hasOwnProperty('toString')) {\n\t this.toString = properties.toString;\n\t }\n\t },\n\n\t /**\n\t * Creates a copy of this object.\n\t *\n\t * @return {Object} The clone.\n\t *\n\t * @example\n\t *\n\t * var clone = instance.clone();\n\t */\n\t clone: function () {\n\t return this.init.prototype.extend(this);\n\t }\n\t };\n\t }());\n\n\t /**\n\t * An array of 32-bit words.\n\t *\n\t * @property {Array} words The array of 32-bit words.\n\t * @property {number} sigBytes The number of significant bytes in this word array.\n\t */\n\t var WordArray = C_lib.WordArray = Base.extend({\n\t /**\n\t * Initializes a newly created word array.\n\t *\n\t * @param {Array} words (Optional) An array of 32-bit words.\n\t * @param {number} sigBytes (Optional) The number of significant bytes in the words.\n\t *\n\t * @example\n\t *\n\t * var wordArray = CryptoJS.lib.WordArray.create();\n\t * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]);\n\t * var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6);\n\t */\n\t init: function (words, sigBytes) {\n\t words = this.words = words || [];\n\n\t if (sigBytes != undefined) {\n\t this.sigBytes = sigBytes;\n\t } else {\n\t this.sigBytes = words.length * 4;\n\t }\n\t },\n\n\t /**\n\t * Converts this word array to a string.\n\t *\n\t * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex\n\t *\n\t * @return {string} The stringified word array.\n\t *\n\t * @example\n\t *\n\t * var string = wordArray + '';\n\t * var string = wordArray.toString();\n\t * var string = wordArray.toString(CryptoJS.enc.Utf8);\n\t */\n\t toString: function (encoder) {\n\t return (encoder || Hex).stringify(this);\n\t },\n\n\t /**\n\t * Concatenates a word array to this word array.\n\t *\n\t * @param {WordArray} wordArray The word array to append.\n\t *\n\t * @return {WordArray} This word array.\n\t *\n\t * @example\n\t *\n\t * wordArray1.concat(wordArray2);\n\t */\n\t concat: function (wordArray) {\n\t // Shortcuts\n\t var thisWords = this.words;\n\t var thatWords = wordArray.words;\n\t var thisSigBytes = this.sigBytes;\n\t var thatSigBytes = wordArray.sigBytes;\n\n\t // Clamp excess bits\n\t this.clamp();\n\n\t // Concat\n\t if (thisSigBytes % 4) {\n\t // Copy one byte at a time\n\t for (var i = 0; i < thatSigBytes; i++) {\n\t var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n\t thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8);\n\t }\n\t } else {\n\t // Copy one word at a time\n\t for (var i = 0; i < thatSigBytes; i += 4) {\n\t thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2];\n\t }\n\t }\n\t this.sigBytes += thatSigBytes;\n\n\t // Chainable\n\t return this;\n\t },\n\n\t /**\n\t * Removes insignificant bits.\n\t *\n\t * @example\n\t *\n\t * wordArray.clamp();\n\t */\n\t clamp: function () {\n\t // Shortcuts\n\t var words = this.words;\n\t var sigBytes = this.sigBytes;\n\n\t // Clamp\n\t words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8);\n\t words.length = Math.ceil(sigBytes / 4);\n\t },\n\n\t /**\n\t * Creates a copy of this word array.\n\t *\n\t * @return {WordArray} The clone.\n\t *\n\t * @example\n\t *\n\t * var clone = wordArray.clone();\n\t */\n\t clone: function () {\n\t var clone = Base.clone.call(this);\n\t clone.words = this.words.slice(0);\n\n\t return clone;\n\t },\n\n\t /**\n\t * Creates a word array filled with random bytes.\n\t *\n\t * @param {number} nBytes The number of random bytes to generate.\n\t *\n\t * @return {WordArray} The random word array.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var wordArray = CryptoJS.lib.WordArray.random(16);\n\t */\n\t random: function (nBytes) {\n\t var words = [];\n\n\t var r = (function (m_w) {\n\t var m_w = m_w;\n\t var m_z = 0x3ade68b1;\n\t var mask = 0xffffffff;\n\n\t return function () {\n\t m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask;\n\t m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask;\n\t var result = ((m_z << 0x10) + m_w) & mask;\n\t result /= 0x100000000;\n\t result += 0.5;\n\t return result * (Math.random() > .5 ? 1 : -1);\n\t }\n\t });\n\n\t for (var i = 0, rcache; i < nBytes; i += 4) {\n\t var _r = r((rcache || Math.random()) * 0x100000000);\n\n\t rcache = _r() * 0x3ade67b7;\n\t words.push((_r() * 0x100000000) | 0);\n\t }\n\n\t return new WordArray.init(words, nBytes);\n\t }\n\t });\n\n\t /**\n\t * Encoder namespace.\n\t */\n\t var C_enc = C.enc = {};\n\n\t /**\n\t * Hex encoding strategy.\n\t */\n\t var Hex = C_enc.Hex = {\n\t /**\n\t * Converts a word array to a hex string.\n\t *\n\t * @param {WordArray} wordArray The word array.\n\t *\n\t * @return {string} The hex string.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var hexString = CryptoJS.enc.Hex.stringify(wordArray);\n\t */\n\t stringify: function (wordArray) {\n\t // Shortcuts\n\t var words = wordArray.words;\n\t var sigBytes = wordArray.sigBytes;\n\n\t // Convert\n\t var hexChars = [];\n\t for (var i = 0; i < sigBytes; i++) {\n\t var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n\t hexChars.push((bite >>> 4).toString(16));\n\t hexChars.push((bite & 0x0f).toString(16));\n\t }\n\n\t return hexChars.join('');\n\t },\n\n\t /**\n\t * Converts a hex string to a word array.\n\t *\n\t * @param {string} hexStr The hex string.\n\t *\n\t * @return {WordArray} The word array.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var wordArray = CryptoJS.enc.Hex.parse(hexString);\n\t */\n\t parse: function (hexStr) {\n\t // Shortcut\n\t var hexStrLength = hexStr.length;\n\n\t // Convert\n\t var words = [];\n\t for (var i = 0; i < hexStrLength; i += 2) {\n\t words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);\n\t }\n\n\t return new WordArray.init(words, hexStrLength / 2);\n\t }\n\t };\n\n\t /**\n\t * Latin1 encoding strategy.\n\t */\n\t var Latin1 = C_enc.Latin1 = {\n\t /**\n\t * Converts a word array to a Latin1 string.\n\t *\n\t * @param {WordArray} wordArray The word array.\n\t *\n\t * @return {string} The Latin1 string.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);\n\t */\n\t stringify: function (wordArray) {\n\t // Shortcuts\n\t var words = wordArray.words;\n\t var sigBytes = wordArray.sigBytes;\n\n\t // Convert\n\t var latin1Chars = [];\n\t for (var i = 0; i < sigBytes; i++) {\n\t var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;\n\t latin1Chars.push(String.fromCharCode(bite));\n\t }\n\n\t return latin1Chars.join('');\n\t },\n\n\t /**\n\t * Converts a Latin1 string to a word array.\n\t *\n\t * @param {string} latin1Str The Latin1 string.\n\t *\n\t * @return {WordArray} The word array.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var wordArray = CryptoJS.enc.Latin1.parse(latin1String);\n\t */\n\t parse: function (latin1Str) {\n\t // Shortcut\n\t var latin1StrLength = latin1Str.length;\n\n\t // Convert\n\t var words = [];\n\t for (var i = 0; i < latin1StrLength; i++) {\n\t words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8);\n\t }\n\n\t return new WordArray.init(words, latin1StrLength);\n\t }\n\t };\n\n\t /**\n\t * UTF-8 encoding strategy.\n\t */\n\t var Utf8 = C_enc.Utf8 = {\n\t /**\n\t * Converts a word array to a UTF-8 string.\n\t *\n\t * @param {WordArray} wordArray The word array.\n\t *\n\t * @return {string} The UTF-8 string.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);\n\t */\n\t stringify: function (wordArray) {\n\t try {\n\t return decodeURIComponent(escape(Latin1.stringify(wordArray)));\n\t } catch (e) {\n\t throw new Error('Malformed UTF-8 data');\n\t }\n\t },\n\n\t /**\n\t * Converts a UTF-8 string to a word array.\n\t *\n\t * @param {string} utf8Str The UTF-8 string.\n\t *\n\t * @return {WordArray} The word array.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var wordArray = CryptoJS.enc.Utf8.parse(utf8String);\n\t */\n\t parse: function (utf8Str) {\n\t return Latin1.parse(unescape(encodeURIComponent(utf8Str)));\n\t }\n\t };\n\n\t /**\n\t * Abstract buffered block algorithm template.\n\t *\n\t * The property blockSize must be implemented in a concrete subtype.\n\t *\n\t * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0\n\t */\n\t var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({\n\t /**\n\t * Resets this block algorithm's data buffer to its initial state.\n\t *\n\t * @example\n\t *\n\t * bufferedBlockAlgorithm.reset();\n\t */\n\t reset: function () {\n\t // Initial values\n\t this._data = new WordArray.init();\n\t this._nDataBytes = 0;\n\t },\n\n\t /**\n\t * Adds new data to this block algorithm's buffer.\n\t *\n\t * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8.\n\t *\n\t * @example\n\t *\n\t * bufferedBlockAlgorithm._append('data');\n\t * bufferedBlockAlgorithm._append(wordArray);\n\t */\n\t _append: function (data) {\n\t // Convert string to WordArray, else assume WordArray already\n\t if (typeof data == 'string') {\n\t data = Utf8.parse(data);\n\t }\n\n\t // Append\n\t this._data.concat(data);\n\t this._nDataBytes += data.sigBytes;\n\t },\n\n\t /**\n\t * Processes available data blocks.\n\t *\n\t * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype.\n\t *\n\t * @param {boolean} doFlush Whether all blocks and partial blocks should be processed.\n\t *\n\t * @return {WordArray} The processed data.\n\t *\n\t * @example\n\t *\n\t * var processedData = bufferedBlockAlgorithm._process();\n\t * var processedData = bufferedBlockAlgorithm._process(!!'flush');\n\t */\n\t _process: function (doFlush) {\n\t // Shortcuts\n\t var data = this._data;\n\t var dataWords = data.words;\n\t var dataSigBytes = data.sigBytes;\n\t var blockSize = this.blockSize;\n\t var blockSizeBytes = blockSize * 4;\n\n\t // Count blocks ready\n\t var nBlocksReady = dataSigBytes / blockSizeBytes;\n\t if (doFlush) {\n\t // Round up to include partial blocks\n\t nBlocksReady = Math.ceil(nBlocksReady);\n\t } else {\n\t // Round down to include only full blocks,\n\t // less the number of blocks that must remain in the buffer\n\t nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0);\n\t }\n\n\t // Count words ready\n\t var nWordsReady = nBlocksReady * blockSize;\n\n\t // Count bytes ready\n\t var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes);\n\n\t // Process blocks\n\t if (nWordsReady) {\n\t for (var offset = 0; offset < nWordsReady; offset += blockSize) {\n\t // Perform concrete-algorithm logic\n\t this._doProcessBlock(dataWords, offset);\n\t }\n\n\t // Remove processed words\n\t var processedWords = dataWords.splice(0, nWordsReady);\n\t data.sigBytes -= nBytesReady;\n\t }\n\n\t // Return processed words\n\t return new WordArray.init(processedWords, nBytesReady);\n\t },\n\n\t /**\n\t * Creates a copy of this object.\n\t *\n\t * @return {Object} The clone.\n\t *\n\t * @example\n\t *\n\t * var clone = bufferedBlockAlgorithm.clone();\n\t */\n\t clone: function () {\n\t var clone = Base.clone.call(this);\n\t clone._data = this._data.clone();\n\n\t return clone;\n\t },\n\n\t _minBufferSize: 0\n\t });\n\n\t /**\n\t * Abstract hasher template.\n\t *\n\t * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits)\n\t */\n\t var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({\n\t /**\n\t * Configuration options.\n\t */\n\t cfg: Base.extend(),\n\n\t /**\n\t * Initializes a newly created hasher.\n\t *\n\t * @param {Object} cfg (Optional) The configuration options to use for this hash computation.\n\t *\n\t * @example\n\t *\n\t * var hasher = CryptoJS.algo.SHA256.create();\n\t */\n\t init: function (cfg) {\n\t // Apply config defaults\n\t this.cfg = this.cfg.extend(cfg);\n\n\t // Set initial values\n\t this.reset();\n\t },\n\n\t /**\n\t * Resets this hasher to its initial state.\n\t *\n\t * @example\n\t *\n\t * hasher.reset();\n\t */\n\t reset: function () {\n\t // Reset data buffer\n\t BufferedBlockAlgorithm.reset.call(this);\n\n\t // Perform concrete-hasher logic\n\t this._doReset();\n\t },\n\n\t /**\n\t * Updates this hasher with a message.\n\t *\n\t * @param {WordArray|string} messageUpdate The message to append.\n\t *\n\t * @return {Hasher} This hasher.\n\t *\n\t * @example\n\t *\n\t * hasher.update('message');\n\t * hasher.update(wordArray);\n\t */\n\t update: function (messageUpdate) {\n\t // Append\n\t this._append(messageUpdate);\n\n\t // Update the hash\n\t this._process();\n\n\t // Chainable\n\t return this;\n\t },\n\n\t /**\n\t * Finalizes the hash computation.\n\t * Note that the finalize operation is effectively a destructive, read-once operation.\n\t *\n\t * @param {WordArray|string} messageUpdate (Optional) A final message update.\n\t *\n\t * @return {WordArray} The hash.\n\t *\n\t * @example\n\t *\n\t * var hash = hasher.finalize();\n\t * var hash = hasher.finalize('message');\n\t * var hash = hasher.finalize(wordArray);\n\t */\n\t finalize: function (messageUpdate) {\n\t // Final message update\n\t if (messageUpdate) {\n\t this._append(messageUpdate);\n\t }\n\n\t // Perform concrete-hasher logic\n\t var hash = this._doFinalize();\n\n\t return hash;\n\t },\n\n\t blockSize: 512/32,\n\n\t /**\n\t * Creates a shortcut function to a hasher's object interface.\n\t *\n\t * @param {Hasher} hasher The hasher to create a helper for.\n\t *\n\t * @return {Function} The shortcut function.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);\n\t */\n\t _createHelper: function (hasher) {\n\t return function (message, cfg) {\n\t return new hasher.init(cfg).finalize(message);\n\t };\n\t },\n\n\t /**\n\t * Creates a shortcut function to the HMAC's object interface.\n\t *\n\t * @param {Hasher} hasher The hasher to use in this HMAC helper.\n\t *\n\t * @return {Function} The shortcut function.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);\n\t */\n\t _createHmacHelper: function (hasher) {\n\t return function (message, key) {\n\t return new C_algo.HMAC.init(hasher, key).finalize(message);\n\t };\n\t }\n\t });\n\n\t /**\n\t * Algorithm namespace.\n\t */\n\t var C_algo = C.algo = {};\n\n\t return C;\n\t}(Math));\n\n\n\treturn CryptoJS;\n\n}));", + ";(function (root, factory, undef) {\n\tif (typeof exports === \"object\") {\n\t\t// CommonJS\n\t\tmodule.exports = exports = factory(require(\"./core\"), require(\"./x64-core\"));\n\t}\n\telse if (typeof define === \"function\" && define.amd) {\n\t\t// AMD\n\t\tdefine([\"./core\", \"./x64-core\"], factory);\n\t}\n\telse {\n\t\t// Global (browser)\n\t\tfactory(root.CryptoJS);\n\t}\n}(this, function (CryptoJS) {\n\n\t(function (Math) {\n\t // Shortcuts\n\t var C = CryptoJS;\n\t var C_lib = C.lib;\n\t var WordArray = C_lib.WordArray;\n\t var Hasher = C_lib.Hasher;\n\t var C_x64 = C.x64;\n\t var X64Word = C_x64.Word;\n\t var C_algo = C.algo;\n\n\t // Constants tables\n\t var RHO_OFFSETS = [];\n\t var PI_INDEXES = [];\n\t var ROUND_CONSTANTS = [];\n\n\t // Compute Constants\n\t (function () {\n\t // Compute rho offset constants\n\t var x = 1, y = 0;\n\t for (var t = 0; t < 24; t++) {\n\t RHO_OFFSETS[x + 5 * y] = ((t + 1) * (t + 2) / 2) % 64;\n\n\t var newX = y % 5;\n\t var newY = (2 * x + 3 * y) % 5;\n\t x = newX;\n\t y = newY;\n\t }\n\n\t // Compute pi index constants\n\t for (var x = 0; x < 5; x++) {\n\t for (var y = 0; y < 5; y++) {\n\t PI_INDEXES[x + 5 * y] = y + ((2 * x + 3 * y) % 5) * 5;\n\t }\n\t }\n\n\t // Compute round constants\n\t var LFSR = 0x01;\n\t for (var i = 0; i < 24; i++) {\n\t var roundConstantMsw = 0;\n\t var roundConstantLsw = 0;\n\n\t for (var j = 0; j < 7; j++) {\n\t if (LFSR & 0x01) {\n\t var bitPosition = (1 << j) - 1;\n\t if (bitPosition < 32) {\n\t roundConstantLsw ^= 1 << bitPosition;\n\t } else /* if (bitPosition >= 32) */ {\n\t roundConstantMsw ^= 1 << (bitPosition - 32);\n\t }\n\t }\n\n\t // Compute next LFSR\n\t if (LFSR & 0x80) {\n\t // Primitive polynomial over GF(2): x^8 + x^6 + x^5 + x^4 + 1\n\t LFSR = (LFSR << 1) ^ 0x71;\n\t } else {\n\t LFSR <<= 1;\n\t }\n\t }\n\n\t ROUND_CONSTANTS[i] = X64Word.create(roundConstantMsw, roundConstantLsw);\n\t }\n\t }());\n\n\t // Reusable objects for temporary values\n\t var T = [];\n\t (function () {\n\t for (var i = 0; i < 25; i++) {\n\t T[i] = X64Word.create();\n\t }\n\t }());\n\n\t /**\n\t * SHA-3 hash algorithm.\n\t */\n\t var SHA3 = C_algo.SHA3 = Hasher.extend({\n\t /**\n\t * Configuration options.\n\t *\n\t * @property {number} outputLength\n\t * The desired number of bits in the output hash.\n\t * Only values permitted are: 224, 256, 384, 512.\n\t * Default: 512\n\t */\n\t cfg: Hasher.cfg.extend({\n\t outputLength: 512\n\t }),\n\n\t _doReset: function () {\n\t var state = this._state = []\n\t for (var i = 0; i < 25; i++) {\n\t state[i] = new X64Word.init();\n\t }\n\n\t this.blockSize = (1600 - 2 * this.cfg.outputLength) / 32;\n\t },\n\n\t _doProcessBlock: function (M, offset) {\n\t // Shortcuts\n\t var state = this._state;\n\t var nBlockSizeLanes = this.blockSize / 2;\n\n\t // Absorb\n\t for (var i = 0; i < nBlockSizeLanes; i++) {\n\t // Shortcuts\n\t var M2i = M[offset + 2 * i];\n\t var M2i1 = M[offset + 2 * i + 1];\n\n\t // Swap endian\n\t M2i = (\n\t (((M2i << 8) | (M2i >>> 24)) & 0x00ff00ff) |\n\t (((M2i << 24) | (M2i >>> 8)) & 0xff00ff00)\n\t );\n\t M2i1 = (\n\t (((M2i1 << 8) | (M2i1 >>> 24)) & 0x00ff00ff) |\n\t (((M2i1 << 24) | (M2i1 >>> 8)) & 0xff00ff00)\n\t );\n\n\t // Absorb message into state\n\t var lane = state[i];\n\t lane.high ^= M2i1;\n\t lane.low ^= M2i;\n\t }\n\n\t // Rounds\n\t for (var round = 0; round < 24; round++) {\n\t // Theta\n\t for (var x = 0; x < 5; x++) {\n\t // Mix column lanes\n\t var tMsw = 0, tLsw = 0;\n\t for (var y = 0; y < 5; y++) {\n\t var lane = state[x + 5 * y];\n\t tMsw ^= lane.high;\n\t tLsw ^= lane.low;\n\t }\n\n\t // Temporary values\n\t var Tx = T[x];\n\t Tx.high = tMsw;\n\t Tx.low = tLsw;\n\t }\n\t for (var x = 0; x < 5; x++) {\n\t // Shortcuts\n\t var Tx4 = T[(x + 4) % 5];\n\t var Tx1 = T[(x + 1) % 5];\n\t var Tx1Msw = Tx1.high;\n\t var Tx1Lsw = Tx1.low;\n\n\t // Mix surrounding columns\n\t var tMsw = Tx4.high ^ ((Tx1Msw << 1) | (Tx1Lsw >>> 31));\n\t var tLsw = Tx4.low ^ ((Tx1Lsw << 1) | (Tx1Msw >>> 31));\n\t for (var y = 0; y < 5; y++) {\n\t var lane = state[x + 5 * y];\n\t lane.high ^= tMsw;\n\t lane.low ^= tLsw;\n\t }\n\t }\n\n\t // Rho Pi\n\t for (var laneIndex = 1; laneIndex < 25; laneIndex++) {\n\t // Shortcuts\n\t var lane = state[laneIndex];\n\t var laneMsw = lane.high;\n\t var laneLsw = lane.low;\n\t var rhoOffset = RHO_OFFSETS[laneIndex];\n\n\t // Rotate lanes\n\t if (rhoOffset < 32) {\n\t var tMsw = (laneMsw << rhoOffset) | (laneLsw >>> (32 - rhoOffset));\n\t var tLsw = (laneLsw << rhoOffset) | (laneMsw >>> (32 - rhoOffset));\n\t } else /* if (rhoOffset >= 32) */ {\n\t var tMsw = (laneLsw << (rhoOffset - 32)) | (laneMsw >>> (64 - rhoOffset));\n\t var tLsw = (laneMsw << (rhoOffset - 32)) | (laneLsw >>> (64 - rhoOffset));\n\t }\n\n\t // Transpose lanes\n\t var TPiLane = T[PI_INDEXES[laneIndex]];\n\t TPiLane.high = tMsw;\n\t TPiLane.low = tLsw;\n\t }\n\n\t // Rho pi at x = y = 0\n\t var T0 = T[0];\n\t var state0 = state[0];\n\t T0.high = state0.high;\n\t T0.low = state0.low;\n\n\t // Chi\n\t for (var x = 0; x < 5; x++) {\n\t for (var y = 0; y < 5; y++) {\n\t // Shortcuts\n\t var laneIndex = x + 5 * y;\n\t var lane = state[laneIndex];\n\t var TLane = T[laneIndex];\n\t var Tx1Lane = T[((x + 1) % 5) + 5 * y];\n\t var Tx2Lane = T[((x + 2) % 5) + 5 * y];\n\n\t // Mix rows\n\t lane.high = TLane.high ^ (~Tx1Lane.high & Tx2Lane.high);\n\t lane.low = TLane.low ^ (~Tx1Lane.low & Tx2Lane.low);\n\t }\n\t }\n\n\t // Iota\n\t var lane = state[0];\n\t var roundConstant = ROUND_CONSTANTS[round];\n\t lane.high ^= roundConstant.high;\n\t lane.low ^= roundConstant.low;;\n\t }\n\t },\n\n\t _doFinalize: function () {\n\t // Shortcuts\n\t var data = this._data;\n\t var dataWords = data.words;\n\t var nBitsTotal = this._nDataBytes * 8;\n\t var nBitsLeft = data.sigBytes * 8;\n\t var blockSizeBits = this.blockSize * 32;\n\n\t // Add padding\n\t dataWords[nBitsLeft >>> 5] |= 0x1 << (24 - nBitsLeft % 32);\n\t dataWords[((Math.ceil((nBitsLeft + 1) / blockSizeBits) * blockSizeBits) >>> 5) - 1] |= 0x80;\n\t data.sigBytes = dataWords.length * 4;\n\n\t // Hash final blocks\n\t this._process();\n\n\t // Shortcuts\n\t var state = this._state;\n\t var outputLengthBytes = this.cfg.outputLength / 8;\n\t var outputLengthLanes = outputLengthBytes / 8;\n\n\t // Squeeze\n\t var hashWords = [];\n\t for (var i = 0; i < outputLengthLanes; i++) {\n\t // Shortcuts\n\t var lane = state[i];\n\t var laneMsw = lane.high;\n\t var laneLsw = lane.low;\n\n\t // Swap endian\n\t laneMsw = (\n\t (((laneMsw << 8) | (laneMsw >>> 24)) & 0x00ff00ff) |\n\t (((laneMsw << 24) | (laneMsw >>> 8)) & 0xff00ff00)\n\t );\n\t laneLsw = (\n\t (((laneLsw << 8) | (laneLsw >>> 24)) & 0x00ff00ff) |\n\t (((laneLsw << 24) | (laneLsw >>> 8)) & 0xff00ff00)\n\t );\n\n\t // Squeeze state to retrieve hash\n\t hashWords.push(laneLsw);\n\t hashWords.push(laneMsw);\n\t }\n\n\t // Return final computed hash\n\t return new WordArray.init(hashWords, outputLengthBytes);\n\t },\n\n\t clone: function () {\n\t var clone = Hasher.clone.call(this);\n\n\t var state = clone._state = this._state.slice(0);\n\t for (var i = 0; i < 25; i++) {\n\t state[i] = state[i].clone();\n\t }\n\n\t return clone;\n\t }\n\t });\n\n\t /**\n\t * Shortcut function to the hasher's object interface.\n\t *\n\t * @param {WordArray|string} message The message to hash.\n\t *\n\t * @return {WordArray} The hash.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var hash = CryptoJS.SHA3('message');\n\t * var hash = CryptoJS.SHA3(wordArray);\n\t */\n\t C.SHA3 = Hasher._createHelper(SHA3);\n\n\t /**\n\t * Shortcut function to the HMAC's object interface.\n\t *\n\t * @param {WordArray|string} message The message to hash.\n\t * @param {WordArray|string} key The secret key.\n\t *\n\t * @return {WordArray} The HMAC.\n\t *\n\t * @static\n\t *\n\t * @example\n\t *\n\t * var hmac = CryptoJS.HmacSHA3(message, key);\n\t */\n\t C.HmacSHA3 = Hasher._createHmacHelper(SHA3);\n\t}(Math));\n\n\n\treturn CryptoJS.SHA3;\n\n}));", + ";(function (root, factory) {\n\tif (typeof exports === \"object\") {\n\t\t// CommonJS\n\t\tmodule.exports = exports = factory(require(\"./core\"));\n\t}\n\telse if (typeof define === \"function\" && define.amd) {\n\t\t// AMD\n\t\tdefine([\"./core\"], factory);\n\t}\n\telse {\n\t\t// Global (browser)\n\t\tfactory(root.CryptoJS);\n\t}\n}(this, function (CryptoJS) {\n\n\t(function (undefined) {\n\t // Shortcuts\n\t var C = CryptoJS;\n\t var C_lib = C.lib;\n\t var Base = C_lib.Base;\n\t var X32WordArray = C_lib.WordArray;\n\n\t /**\n\t * x64 namespace.\n\t */\n\t var C_x64 = C.x64 = {};\n\n\t /**\n\t * A 64-bit word.\n\t */\n\t var X64Word = C_x64.Word = Base.extend({\n\t /**\n\t * Initializes a newly created 64-bit word.\n\t *\n\t * @param {number} high The high 32 bits.\n\t * @param {number} low The low 32 bits.\n\t *\n\t * @example\n\t *\n\t * var x64Word = CryptoJS.x64.Word.create(0x00010203, 0x04050607);\n\t */\n\t init: function (high, low) {\n\t this.high = high;\n\t this.low = low;\n\t }\n\n\t /**\n\t * Bitwise NOTs this word.\n\t *\n\t * @return {X64Word} A new x64-Word object after negating.\n\t *\n\t * @example\n\t *\n\t * var negated = x64Word.not();\n\t */\n\t // not: function () {\n\t // var high = ~this.high;\n\t // var low = ~this.low;\n\n\t // return X64Word.create(high, low);\n\t // },\n\n\t /**\n\t * Bitwise ANDs this word with the passed word.\n\t *\n\t * @param {X64Word} word The x64-Word to AND with this word.\n\t *\n\t * @return {X64Word} A new x64-Word object after ANDing.\n\t *\n\t * @example\n\t *\n\t * var anded = x64Word.and(anotherX64Word);\n\t */\n\t // and: function (word) {\n\t // var high = this.high & word.high;\n\t // var low = this.low & word.low;\n\n\t // return X64Word.create(high, low);\n\t // },\n\n\t /**\n\t * Bitwise ORs this word with the passed word.\n\t *\n\t * @param {X64Word} word The x64-Word to OR with this word.\n\t *\n\t * @return {X64Word} A new x64-Word object after ORing.\n\t *\n\t * @example\n\t *\n\t * var ored = x64Word.or(anotherX64Word);\n\t */\n\t // or: function (word) {\n\t // var high = this.high | word.high;\n\t // var low = this.low | word.low;\n\n\t // return X64Word.create(high, low);\n\t // },\n\n\t /**\n\t * Bitwise XORs this word with the passed word.\n\t *\n\t * @param {X64Word} word The x64-Word to XOR with this word.\n\t *\n\t * @return {X64Word} A new x64-Word object after XORing.\n\t *\n\t * @example\n\t *\n\t * var xored = x64Word.xor(anotherX64Word);\n\t */\n\t // xor: function (word) {\n\t // var high = this.high ^ word.high;\n\t // var low = this.low ^ word.low;\n\n\t // return X64Word.create(high, low);\n\t // },\n\n\t /**\n\t * Shifts this word n bits to the left.\n\t *\n\t * @param {number} n The number of bits to shift.\n\t *\n\t * @return {X64Word} A new x64-Word object after shifting.\n\t *\n\t * @example\n\t *\n\t * var shifted = x64Word.shiftL(25);\n\t */\n\t // shiftL: function (n) {\n\t // if (n < 32) {\n\t // var high = (this.high << n) | (this.low >>> (32 - n));\n\t // var low = this.low << n;\n\t // } else {\n\t // var high = this.low << (n - 32);\n\t // var low = 0;\n\t // }\n\n\t // return X64Word.create(high, low);\n\t // },\n\n\t /**\n\t * Shifts this word n bits to the right.\n\t *\n\t * @param {number} n The number of bits to shift.\n\t *\n\t * @return {X64Word} A new x64-Word object after shifting.\n\t *\n\t * @example\n\t *\n\t * var shifted = x64Word.shiftR(7);\n\t */\n\t // shiftR: function (n) {\n\t // if (n < 32) {\n\t // var low = (this.low >>> n) | (this.high << (32 - n));\n\t // var high = this.high >>> n;\n\t // } else {\n\t // var low = this.high >>> (n - 32);\n\t // var high = 0;\n\t // }\n\n\t // return X64Word.create(high, low);\n\t // },\n\n\t /**\n\t * Rotates this word n bits to the left.\n\t *\n\t * @param {number} n The number of bits to rotate.\n\t *\n\t * @return {X64Word} A new x64-Word object after rotating.\n\t *\n\t * @example\n\t *\n\t * var rotated = x64Word.rotL(25);\n\t */\n\t // rotL: function (n) {\n\t // return this.shiftL(n).or(this.shiftR(64 - n));\n\t // },\n\n\t /**\n\t * Rotates this word n bits to the right.\n\t *\n\t * @param {number} n The number of bits to rotate.\n\t *\n\t * @return {X64Word} A new x64-Word object after rotating.\n\t *\n\t * @example\n\t *\n\t * var rotated = x64Word.rotR(7);\n\t */\n\t // rotR: function (n) {\n\t // return this.shiftR(n).or(this.shiftL(64 - n));\n\t // },\n\n\t /**\n\t * Adds this word with the passed word.\n\t *\n\t * @param {X64Word} word The x64-Word to add with this word.\n\t *\n\t * @return {X64Word} A new x64-Word object after adding.\n\t *\n\t * @example\n\t *\n\t * var added = x64Word.add(anotherX64Word);\n\t */\n\t // add: function (word) {\n\t // var low = (this.low + word.low) | 0;\n\t // var carry = (low >>> 0) < (this.low >>> 0) ? 1 : 0;\n\t // var high = (this.high + word.high + carry) | 0;\n\n\t // return X64Word.create(high, low);\n\t // }\n\t });\n\n\t /**\n\t * An array of 64-bit words.\n\t *\n\t * @property {Array} words The array of CryptoJS.x64.Word objects.\n\t * @property {number} sigBytes The number of significant bytes in this word array.\n\t */\n\t var X64WordArray = C_x64.WordArray = Base.extend({\n\t /**\n\t * Initializes a newly created word array.\n\t *\n\t * @param {Array} words (Optional) An array of CryptoJS.x64.Word objects.\n\t * @param {number} sigBytes (Optional) The number of significant bytes in the words.\n\t *\n\t * @example\n\t *\n\t * var wordArray = CryptoJS.x64.WordArray.create();\n\t *\n\t * var wordArray = CryptoJS.x64.WordArray.create([\n\t * CryptoJS.x64.Word.create(0x00010203, 0x04050607),\n\t * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f)\n\t * ]);\n\t *\n\t * var wordArray = CryptoJS.x64.WordArray.create([\n\t * CryptoJS.x64.Word.create(0x00010203, 0x04050607),\n\t * CryptoJS.x64.Word.create(0x18191a1b, 0x1c1d1e1f)\n\t * ], 10);\n\t */\n\t init: function (words, sigBytes) {\n\t words = this.words = words || [];\n\n\t if (sigBytes != undefined) {\n\t this.sigBytes = sigBytes;\n\t } else {\n\t this.sigBytes = words.length * 8;\n\t }\n\t },\n\n\t /**\n\t * Converts this 64-bit word array to a 32-bit word array.\n\t *\n\t * @return {CryptoJS.lib.WordArray} This word array's data as a 32-bit word array.\n\t *\n\t * @example\n\t *\n\t * var x32WordArray = x64WordArray.toX32();\n\t */\n\t toX32: function () {\n\t // Shortcuts\n\t var x64Words = this.words;\n\t var x64WordsLength = x64Words.length;\n\n\t // Convert\n\t var x32Words = [];\n\t for (var i = 0; i < x64WordsLength; i++) {\n\t var x64Word = x64Words[i];\n\t x32Words.push(x64Word.high);\n\t x32Words.push(x64Word.low);\n\t }\n\n\t return X32WordArray.create(x32Words, this.sigBytes);\n\t },\n\n\t /**\n\t * Creates a copy of this word array.\n\t *\n\t * @return {X64WordArray} The clone.\n\t *\n\t * @example\n\t *\n\t * var clone = x64WordArray.clone();\n\t */\n\t clone: function () {\n\t var clone = Base.clone.call(this);\n\n\t // Clone \"words\" array\n\t var words = clone.words = this.words.slice(0);\n\n\t // Clone each X64Word object\n\t var wordsLength = words.length;\n\t for (var i = 0; i < wordsLength; i++) {\n\t words[i] = words[i].clone();\n\t }\n\n\t return clone;\n\t }\n\t });\n\t}());\n\n\n\treturn CryptoJS;\n\n}));", + "/*! 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');\nweb3.eth.namereg = require('./lib/web3/namereg');\nweb3.eth.sendIBANTransaction = require('./lib/web3/transfer');\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 1f1fcb189..a73cde830 100644 --- a/libjsqrc/ethereumjs/dist/web3.min.js +++ b/libjsqrc/ethereumjs/dist/web3.min.js @@ -1,2 +1,2 @@ -require=function t(e,n,r){function i(a,s){if(!n[a]){if(!e[a]){var u="function"==typeof require&&require;if(!s&&u)return u(a,!0);if(o)return o(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var 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 +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())},b=function(t){return i.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:h,formatOutputUInt:m,formatOutputReal:d,formatOutputUReal:g,formatOutputBool:y,formatOutputBytes:v,formatOutputDynamicBytes:b,formatOutputAddress:w}},{"../utils/config":5,"../utils/utils":7,"./param":3,"bignumber.js":"bignumber.js"}],3:[function(t,e,n){var r=t("../utils/utils"),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:500,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])?a.inputDefaultBlockNumberFormatter(t.pop()):void 0},u.prototype.toPayload=function(t){var e={};return t.length>this._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},u.prototype.signature=function(){return s(this._name).slice(0,8)},u.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}},u.prototype.call=function(){var t=Array.prototype.slice.call(arguments).filter(function(t){return void 0!==t}),e=this.extractCallback(t),n=this.extractDefaultBlock(t),i=this.toPayload(t);if(!e){var o=r.eth.call(i,n);return this.unpackOutput(o)}var a=this;r.eth.call(i,n,function(t,n){e(t,a.unpackOutput(n))})},u.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)},u.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)},u.prototype.displayName=function(){return o.extractDisplayName(this._name)},u.prototype.typeName=function(){return o.extractTypeName(this._name)},u.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}},u.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))},u.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=u},{"../solidity/coder":1,"../utils/sha3":6,"../utils/utils":7,"../web3":9,"./formatters":17}],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),e.setRequestHeader("Content-type","application/json");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),n.setRequestHeader("Content-type","application/json");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.isPolling=!1))};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,this.provider&&!this.isPolling&&(this.poll(),this.isPolling=!0)},s.prototype.startPolling=function(t,e,n,r){this.polls["poll_"+e]={data:t,id:e,callback:n,uninstall:r}},s.prototype.stopPolling=function(t){delete this.polls["poll_"+t]},s.prototype.reset=function(){for(var t in this.polls)this.polls[t].uninstall();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),0!==Object.keys(this.polls).length){if(!this.provider)return void console.error(a.InvalidProvider());var t=[],e=[];for(var n in this.polls)t.push(this.polls[n].data),e.push(n);if(0!==t.length){var s=r.getInstance().toBatchPayload(t),u=this;this.provider.sendAsync(s,function(t,n){if(!t){if(!i.isArray(n))throw a.InvalidResponse(n);n.map(function(t,n){var r=e[n];return u.polls[r]?(t.callback=u.polls[r].callback,t):!1}).filter(function(t){return!!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.shift(),this.params=0,"eth_newBlockFilter";case"pending":return t.shift(),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],b=p[(h+1)%5],w=b.high,_=b.low,m=v.high^(w<<1|_>>>31),d=v.low^(_<<1|w>>>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,j+l.e+1,L);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>G)l.c=l.e=null;else if(M>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=j,y=L;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,w)?0|r:L,!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)>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",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>G?t.c=t.e=null:t.en?null!=(t=i[n++]):void 0};return a(e="DECIMAL_PLACES")&&W(t,0,A,2,e)&&(j=0|t),r[e]=j,a(e="ROUNDING_MODE")&&W(t,0,8,2,e)&&(L=0|t),r[e]=L,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)&&(M=0|t[0],G=0|t[1]):W(t,-A,A,2,e)&&(0|t?M=-(G=0|(0>t?-t:t)):z&&D(2,e+" cannot be zero",t))),r[e]=[M,G],a(e="ERRORS")&&(t===!!t||1===t||0===t?(C=0,W=(z=!!t)?P:s):z&&D(2,e+b,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+b,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:j,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,b,w,_,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),b=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)b.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,w=T.slice(0,A),_=w.length;A>_;w[_++]=0);k=D.slice(),k.unshift(0),O=D[0],D[1]>=c/2&&O++;do{if(m=0,l=n(D,w,A,_),0>l){if(x=w[0],A!=_&&(x=x*c+(w[1]||0)),m=v(x/O),m>1)for(m>=c&&(m=c-1),d=t(D,m,c),g=d.length,_=w.length;1==n(d,w,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(w,d,_,c),_=w.length,-1==l)for(;n(D,w,A,_)<1;)m++,r(w,_>A?k:D,_,c),_=w.length}else 0===l&&(m++,w=[0]);b[p++]=m,w[0]?w[_++]=T[B]||0:(w=[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),j,L)},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==L?-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"+b,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,w)?0|n:L),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=j+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=w,w=_,_=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=w[--u]%v,p=w[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,w)?0|n:L,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=G,G=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,L).minus(h).abs().cmp(E(c,r,a,L).minus(h).abs())<1?[g.toString(),y.toString()]:[c.toString(),r.toString()],G=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,L):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,b=" not a boolean or binary digit",w="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/coin.html b/libjsqrc/ethereumjs/example/coin.html deleted file mode 100644 index 6c743a2a6..000000000 --- a/libjsqrc/ethereumjs/example/coin.html +++ /dev/null @@ -1,153 +0,0 @@ - - -JevCoin - - - - - -

JevCoin

-
- Balance - -
- -
- Address: - - Amount: - - - -
- -
- - - - -
AddressBalance
- - - - - - - diff --git a/libjsqrc/ethereumjs/example/event_inc.html b/libjsqrc/ethereumjs/example/event_inc.html index 01671c475..e4a1211b4 100644 --- a/libjsqrc/ethereumjs/example/event_inc.html +++ b/libjsqrc/ethereumjs/example/event_inc.html @@ -25,6 +25,7 @@ var address; var contract; + var inc; var update = function (err, x) { document.getElementById('result').textContent = JSON.stringify(x, null, 2); @@ -55,8 +56,8 @@ } }); - contract.Incremented({odd: true}).watch(update); - + inc = contract.Incremented({odd: true}); + inc.watch(update); }; var counter = 0; diff --git a/libjsqrc/ethereumjs/gulpfile.js b/libjsqrc/ethereumjs/gulpfile.js index 558c1181a..360c5242b 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', [], function () { +gulp.task('buildStandalone', ['clean'], function () { return browserify(browserifyOptions) .require('./' + src + '.js', {expose: 'web3'}) .require('bignumber.js') // expose it to dapp users diff --git a/libjsqrc/ethereumjs/lib/utils/config.js b/libjsqrc/ethereumjs/lib/utils/config.js index d25b5d7ba..2070047c9 100644 --- a/libjsqrc/ethereumjs/lib/utils/config.js +++ b/libjsqrc/ethereumjs/lib/utils/config.js @@ -71,7 +71,7 @@ module.exports = { ETH_SIGNATURE_LENGTH: 4, ETH_UNITS: ETH_UNITS, ETH_BIGNUMBER_ROUNDING_MODE: { ROUNDING_MODE: BigNumber.ROUND_DOWN }, - ETH_POLLING_TIMEOUT: 1000, + ETH_POLLING_TIMEOUT: 1000/2, defaultBlock: 'latest', defaultAccount: undefined }; diff --git a/libjsqrc/ethereumjs/lib/version.json b/libjsqrc/ethereumjs/lib/version.json index 8fd887d4d..424d60960 100644 --- a/libjsqrc/ethereumjs/lib/version.json +++ b/libjsqrc/ethereumjs/lib/version.json @@ -1,3 +1,3 @@ { - "version": "0.5.0" + "version": "0.6.0" } diff --git a/libjsqrc/ethereumjs/lib/web3.js b/libjsqrc/ethereumjs/lib/web3.js index 394ae450b..66eea6ee1 100644 --- a/libjsqrc/ethereumjs/lib/web3.js +++ b/libjsqrc/ethereumjs/lib/web3.js @@ -34,7 +34,6 @@ var Filter = require('./web3/filter'); var utils = require('./utils/utils'); var formatters = require('./web3/formatters'); var RequestManager = require('./web3/requestmanager'); -var Method = require('./web3/method'); var c = require('./utils/config'); var Property = require('./web3/property'); var Batch = require('./web3/batch'); @@ -94,8 +93,7 @@ web3.eth.filter = function (fil, eventParams, options, formatter) { return fil(eventParams, options); } - // what outputLogFormatter? that's wrong - //return new Filter(fil, watches.eth(), formatters.outputLogFormatter); + // output logs works for blockFilter and pendingTransaction filters? return new Filter(fil, watches.eth(), formatter || formatters.outputLogFormatter); }; /*jshint maxparams:3 */ @@ -150,6 +148,23 @@ Object.defineProperty(web3.eth, 'defaultAccount', { } }); + +// EXTEND +web3._extend = function(extension){ + /*jshint maxcomplexity: 6 */ + + if(extension.property && !web3[extension.property]) + web3[extension.property] = {}; + + setupMethods(web3[extension.property] || web3, extension.methods || []); + setupProperties(web3[extension.property] || web3, extension.properties || []); +}; +web3._extend.formatters = formatters; +web3._extend.utils = utils; +web3._extend.Method = require('./web3/method'); +web3._extend.Property = require('./web3/property'); + + /// setups all api methods setupProperties(web3, web3Properties); setupMethods(web3.net, net.methods); @@ -159,17 +174,5 @@ 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 23297f1f0..87a2b290c 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/filter.js b/libjsqrc/ethereumjs/lib/web3/filter.js index bf66ab3ed..bb760c3dc 100644 --- a/libjsqrc/ethereumjs/lib/web3/filter.js +++ b/libjsqrc/ethereumjs/lib/web3/filter.js @@ -74,21 +74,36 @@ var getOptions = function (options) { }; }; -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); +/** +Adds the callback and sets up the methods, to iterate over the results. + +@method getLogsAtStart +@param {Object} self +@param {funciton} +*/ +var getLogsAtStart = function(self, callback){ + // call getFilterLogs for the first watch callback start + if (!utils.isString(self.options)) { + self.get(function (err, messages) { + // don't send all the responses to all the watches again... just to self one + if (err) { + callback(err); + } + + messages.forEach(function (message) { + callback(null, message); + }); + }); + } }; -Filter.prototype.watch = function (callback) { - this.callbacks.push(callback); - var self = this; +/** +Adds the callback and sets up the methods, to iterate over the results. + +@method pollFilter +@param {Object} self +*/ +var pollFilter = function(self) { var onMessage = function (error, messages) { if (error) { @@ -105,29 +120,55 @@ Filter.prototype.watch = function (callback) { }); }; - // 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); - } + RequestManager.getInstance().startPolling({ + method: self.implementation.poll.call, + params: [self.filterId], + }, self.filterId, onMessage, self.stopWatching.bind(self)); - messages.forEach(function (message) { - callback(null, message); +}; + +var Filter = function (options, methods, formatter) { + var self = this; + var implementation = {}; + methods.forEach(function (method) { + method.attachToObject(implementation); + }); + this.options = getOptions(options); + this.implementation = implementation; + this.callbacks = []; + this.pollFilters = []; + this.formatter = formatter; + this.implementation.newFilter(this.options, function(error, id){ + if(error) { + self.callbacks.forEach(function(callback){ + callback(error); }); - }); + } else { + self.filterId = id; + // get filter logs at start + self.callbacks.forEach(function(callback){ + getLogsAtStart(self, callback); + }); + pollFilter(self); + } + }); +}; + +Filter.prototype.watch = function (callback) { + this.callbacks.push(callback); + + if(this.filterId) { + getLogsAtStart(this, callback); + pollFilter(this); } - RequestManager.getInstance().startPolling({ - method: this.implementation.poll.call, - params: [this.filterId], - }, this.filterId, onMessage, this.stopWatching.bind(this)); + return this; }; Filter.prototype.stopWatching = function () { RequestManager.getInstance().stopPolling(this.filterId); - this.implementation.uninstallFilter(this.filterId); + // remove filter async + this.implementation.uninstallFilter(this.filterId, function(){}); this.callbacks = []; }; @@ -149,6 +190,8 @@ Filter.prototype.get = function (callback) { return self.formatter ? self.formatter(log) : log; }); } + + return this; }; module.exports = Filter; diff --git a/libjsqrc/ethereumjs/lib/web3/formatters.js b/libjsqrc/ethereumjs/lib/web3/formatters.js index d45353649..743527e49 100644 --- a/libjsqrc/ethereumjs/lib/web3/formatters.js +++ b/libjsqrc/ethereumjs/lib/web3/formatters.js @@ -89,8 +89,10 @@ var inputTransactionFormatter = function (options){ * @returns {Object} transaction */ var outputTransactionFormatter = function (tx){ - tx.blockNumber = utils.toDecimal(tx.blockNumber); - tx.transactionIndex = utils.toDecimal(tx.transactionIndex); + if(tx.blockNumber !== null) + tx.blockNumber = utils.toDecimal(tx.blockNumber); + if(tx.transactionIndex !== null) + tx.transactionIndex = utils.toDecimal(tx.transactionIndex); tx.nonce = utils.toDecimal(tx.nonce); tx.gas = utils.toDecimal(tx.gas); tx.gasPrice = utils.toBigNumber(tx.gasPrice); @@ -112,7 +114,8 @@ var outputBlockFormatter = function(block) { block.gasUsed = utils.toDecimal(block.gasUsed); block.size = utils.toDecimal(block.size); block.timestamp = utils.toDecimal(block.timestamp); - block.number = utils.toDecimal(block.number); + if(block.number !== null) + block.number = utils.toDecimal(block.number); block.difficulty = utils.toBigNumber(block.difficulty); block.totalDifficulty = utils.toBigNumber(block.totalDifficulty); @@ -135,13 +138,12 @@ var outputBlockFormatter = function(block) { * @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); + if(log.blockNumber !== null) + log.blockNumber = utils.toDecimal(log.blockNumber); + if(log.transactionIndex !== null) + log.transactionIndex = utils.toDecimal(log.transactionIndex); + if(log.logIndex !== null) + log.logIndex = utils.toDecimal(log.logIndex); return log; }; diff --git a/libjsqrc/ethereumjs/lib/web3/function.js b/libjsqrc/ethereumjs/lib/web3/function.js index 1b377be84..c510adf15 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 formatters = require('./formatters'); var sha3 = require('../utils/sha3'); /** @@ -46,6 +47,12 @@ SolidityFunction.prototype.extractCallback = function (args) { } }; +SolidityFunction.prototype.extractDefaultBlock = function (args) { + if (args.length > this._inputTypes.length && !utils.isObject(args[args.length -1])) { + return formatters.inputDefaultBlockNumberFormatter(args.pop()); // modify the args array! + } +}; + /** * Should be used to create payload from arguments * @@ -97,15 +104,17 @@ SolidityFunction.prototype.unpackOutput = function (output) { SolidityFunction.prototype.call = function () { var args = Array.prototype.slice.call(arguments).filter(function (a) {return a !== undefined; }); var callback = this.extractCallback(args); + var defaultBlock = this.extractDefaultBlock(args); var payload = this.toPayload(args); + if (!callback) { - var output = web3.eth.call(payload); + var output = web3.eth.call(payload, defaultBlock); return this.unpackOutput(output); } var self = this; - web3.eth.call(payload, function (error, output) { + web3.eth.call(payload, defaultBlock, function (error, output) { callback(error, self.unpackOutput(output)); }); }; diff --git a/libjsqrc/ethereumjs/lib/web3/httpprovider.js b/libjsqrc/ethereumjs/lib/web3/httpprovider.js index fd972c05a..d3ac9cc34 100644 --- a/libjsqrc/ethereumjs/lib/web3/httpprovider.js +++ b/libjsqrc/ethereumjs/lib/web3/httpprovider.js @@ -35,6 +35,7 @@ HttpProvider.prototype.send = function (payload) { var request = new XMLHttpRequest(); request.open('POST', this.host, false); + request.setRequestHeader('Content-type','application/json'); try { request.send(JSON.stringify(payload)); @@ -78,7 +79,8 @@ HttpProvider.prototype.sendAsync = function (payload, callback) { }; request.open('POST', this.host, true); - + request.setRequestHeader('Content-type','application/json'); + try { request.send(JSON.stringify(payload)); } catch(error) { diff --git a/libjsqrc/ethereumjs/lib/web3/property.js b/libjsqrc/ethereumjs/lib/web3/property.js index 4b2b6c566..a2e7282e9 100644 --- a/libjsqrc/ethereumjs/lib/web3/property.js +++ b/libjsqrc/ethereumjs/lib/web3/property.js @@ -29,7 +29,6 @@ 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/requestmanager.js b/libjsqrc/ethereumjs/lib/web3/requestmanager.js index 73a18881a..d46bf0a3c 100644 --- a/libjsqrc/ethereumjs/lib/web3/requestmanager.js +++ b/libjsqrc/ethereumjs/lib/web3/requestmanager.js @@ -43,9 +43,9 @@ var RequestManager = function (provider) { arguments.callee._singletonInstance = this; this.provider = provider; - this.polls = []; + this.polls = {}; this.timeout = null; - this.poll(); + this.isPolling = false; }; /** @@ -140,6 +140,11 @@ RequestManager.prototype.sendBatch = function (data, callback) { */ RequestManager.prototype.setProvider = function (p) { this.provider = p; + + if (this.provider && !this.isPolling) { + this.poll(); + this.isPolling = true; + } }; /*jshint maxparams:4 */ @@ -156,7 +161,7 @@ RequestManager.prototype.setProvider = function (p) { * @todo cleanup number of params */ RequestManager.prototype.startPolling = function (data, pollId, callback, uninstall) { - this.polls.push({data: data, id: pollId, callback: callback, uninstall: uninstall}); + this.polls['poll_'+ pollId] = {data: data, id: pollId, callback: callback, uninstall: uninstall}; }; /*jshint maxparams:3 */ @@ -167,24 +172,19 @@ RequestManager.prototype.startPolling = function (data, pollId, callback, uninst * @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); - } - } + delete this.polls['poll_'+ pollId]; }; /** - * Should be called to reset polling mechanism of request manager + * Should be called to reset the polling mechanism of the request manager * * @method reset */ RequestManager.prototype.reset = function () { - this.polls.forEach(function (poll) { - poll.uninstall(poll.id); - }); - this.polls = []; + for (var key in this.polls) { + this.polls[key].uninstall(); + } + this.polls = {}; if (this.timeout) { clearTimeout(this.timeout); @@ -199,9 +199,10 @@ RequestManager.prototype.reset = function () { * @method poll */ RequestManager.prototype.poll = function () { + /*jshint maxcomplexity: 6 */ this.timeout = setTimeout(this.poll.bind(this), c.ETH_POLLING_TIMEOUT); - if (!this.polls.length) { + if (Object.keys(this.polls).length === 0) { return; } @@ -210,9 +211,18 @@ RequestManager.prototype.poll = function () { return; } - var payload = Jsonrpc.getInstance().toBatchPayload(this.polls.map(function (data) { - return data.data; - })); + var pollsData = []; + var pollsKeys = []; + for (var key in this.polls) { + pollsData.push(this.polls[key].data); + pollsKeys.push(key); + } + + if (pollsData.length === 0) { + return; + } + + var payload = Jsonrpc.getInstance().toBatchPayload(pollsData); var self = this; this.provider.sendAsync(payload, function (error, results) { @@ -220,14 +230,21 @@ RequestManager.prototype.poll = function () { if (error) { return; } - + if (!utils.isArray(results)) { throw errors.InvalidResponse(results); } results.map(function (result, index) { - result.callback = self.polls[index].callback; - return result; + var key = pollsKeys[index]; + // make sure the filter is still installed after arrival of the request + if (self.polls[key]) { + result.callback = self.polls[key].callback; + return result; + } else + return false; + }).filter(function (result) { + return !!result; }).filter(function (result) { var valid = Jsonrpc.getInstance().isValidResponse(result); if (!valid) { diff --git a/libjsqrc/ethereumjs/lib/web3/watches.js b/libjsqrc/ethereumjs/lib/web3/watches.js index 8bcfe207b..6b09fe329 100644 --- a/libjsqrc/ethereumjs/lib/web3/watches.js +++ b/libjsqrc/ethereumjs/lib/web3/watches.js @@ -29,11 +29,11 @@ var eth = function () { switch(type) { case 'latest': - args.pop(); + args.shift(); this.params = 0; return 'eth_newBlockFilter'; case 'pending': - args.pop(); + args.shift(); this.params = 0; return 'eth_newPendingTransactionFilter'; default: diff --git a/libjsqrc/ethereumjs/package.js b/libjsqrc/ethereumjs/package.js index ccf7ddd75..66c3ddb5d 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.5.0', + version: '0.6.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 3ff3028bb..f051c61cd 100644 --- a/libjsqrc/ethereumjs/package.json +++ b/libjsqrc/ethereumjs/package.json @@ -1,7 +1,7 @@ { "name": "web3", "namespace": "ethereum", - "version": "0.5.0", + "version": "0.6.0", "description": "Ethereum JavaScript API, middleware to talk to a ethereum node over RPC", "main": "./index.js", "directories": { @@ -17,11 +17,11 @@ }, "devDependencies": { "bower": ">=1.3.0", - "browserify": ">=6.0", + "browserify": ">=10.0", "chai": "^2.1.1", "coveralls": "^2.11.2", "del": ">=0.1.1", - "exorcist": "^0.1.6", + "exorcist": "^0.4.0", "gulp": ">=3.4.0", "gulp-jshint": ">=1.5.0", "gulp-rename": ">=1.2.0", diff --git a/libjsqrc/ethereumjs/test/contract.js b/libjsqrc/ethereumjs/test/contract.js index 00f9cbcc8..2632575f5 100644 --- a/libjsqrc/ethereumjs/test/contract.js +++ b/libjsqrc/ethereumjs/test/contract.js @@ -66,7 +66,7 @@ describe('web3.eth.contract', function () { provider.injectValidation(function (payload) { if (step === 0) { step = 1; - provider.injectResult(3); + provider.injectResult('0x3'); assert.equal(payload.jsonrpc, '2.0'); assert.equal(payload.method, 'eth_newFilter'); assert.deepEqual(payload.params[0], { @@ -105,7 +105,7 @@ describe('web3.eth.contract', function () { '0000000000000000000000000000000000000000000000000000000000000008' }]]); var r = payload.filter(function (p) { - return p.jsonrpc === '2.0' && p.method === 'eth_getFilterChanges' && p.params[0] === 3; + return p.jsonrpc === '2.0' && p.method === 'eth_getFilterChanges' && p.params[0] === '0x3'; }); assert.equal(r.length > 0, true); } @@ -114,7 +114,8 @@ describe('web3.eth.contract', function () { var contract = web3.eth.contract(desc).at(address); var res = 0; - contract.Changed({from: address}).watch(function(err, result) { + var event = contract.Changed({from: address}); + event.watch(function(err, result) { assert.equal(result.args.from, address); assert.equal(result.args.amount, 1); assert.equal(result.args.t1, 1); @@ -133,6 +134,7 @@ describe('web3.eth.contract', function () { provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032'); var signature = 'balance(address)' var address = '0x1234567890123456789012345678901234567890'; + provider.injectValidation(function (payload) { assert.equal(payload.method, 'eth_call'); assert.deepEqual(payload.params, [{ @@ -147,6 +149,28 @@ describe('web3.eth.contract', function () { assert.deepEqual(new BigNumber(0x32), r); }); + it('should call constant function with default block', function () { + var provider = new FakeHttpProvider(); + web3.setProvider(provider); + web3.reset(); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032'); + var signature = 'balance(address)' + var address = '0x1234567890123456789012345678901234567890'; + + provider.injectValidation(function (payload) { + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: '0x' + sha3(signature).slice(0, 8) + '0000000000000000000000001234567890123456789012345678901234567890', + to: address + }, '0xb']); + }); + + var contract = web3.eth.contract(desc).at(address); + + var r = contract.balance(address, 11); + assert.deepEqual(new BigNumber(0x32), r); + }); + it('should sendTransaction to contract function', function () { var provider = new FakeHttpProvider(); web3.setProvider(provider); @@ -218,6 +242,31 @@ describe('web3.eth.contract', function () { }); + it('should explicitly make a call with optional params and defaultBlock', function () { + + var provider = new FakeHttpProvider(); + web3.setProvider(provider); + web3.reset(); + provider.injectResult('0x0000000000000000000000000000000000000000000000000000000000000032'); + var signature = 'balance(address)'; + var address = '0x1234567890123456789012345678901234567890'; + provider.injectValidation(function (payload) { + assert.equal(payload.method, 'eth_call'); + assert.deepEqual(payload.params, [{ + data: '0x' + sha3(signature).slice(0, 8) + '0000000000000000000000001234567890123456789012345678901234567890', + to: address, + from: address, + gas: '0xc350' + }, '0xb']); + }); + + var contract = web3.eth.contract(desc).at(address); + + var r = contract.balance.call(address, {from: address, gas: 50000}, 11); + assert.deepEqual(new BigNumber(0x32), r); + + }); + it('should sendTransaction with optional params', function () { var provider = new FakeHttpProvider(); web3.setProvider(provider); diff --git a/libjsqrc/ethereumjs/test/formatters.outputBlockFormatter.js b/libjsqrc/ethereumjs/test/formatters.outputBlockFormatter.js index 272250651..a94c87b37 100644 --- a/libjsqrc/ethereumjs/test/formatters.outputBlockFormatter.js +++ b/libjsqrc/ethereumjs/test/formatters.outputBlockFormatter.js @@ -8,38 +8,72 @@ describe('formatters', function () { it('should return the correct value', function () { assert.deepEqual(formatters.outputBlockFormatter({ - hash: '0x34234kjh23kj4234', - parentHash: '0x34234kjh23kj4234', - miner: '0x34234kjh23kj4234', - stateRoot: '0x34234kjh23kj4234', - sha3Uncles: '0x34234kjh23kj4234', - bloom: '0x34234kjh23kj4234', + hash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265', + parentHash: '0x83ffb245cfced97ccc5c75253d6960376d6c6dea93647397a543a72fdaea5265', + miner: '0xdcc6960376d6c6dea93647383ffb245cfced97cf', + stateRoot: '0x54dda68af07643f68739a6e9612ad157a26ae7e2ce81f77842bb5835fbcde583', + sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', + bloom: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265', difficulty: '0x3e8', totalDifficulty: '0x3e8', number: '0x3e8', gasLimit: '0x3e8', gasUsed: '0x3e8', timestamp: '0x3e8', - extraData: '0x34234kjh23kj4234', - nonce: '0x34234kjh23kj4234', - children: ['0x34234kjh23kj4234'], + extraData: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265', + nonce: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265', size: '0x3e8' }), { - hash: '0x34234kjh23kj4234', - parentHash: '0x34234kjh23kj4234', - miner: '0x34234kjh23kj4234', - stateRoot: '0x34234kjh23kj4234', - sha3Uncles: '0x34234kjh23kj4234', - bloom: '0x34234kjh23kj4234', + hash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265', + parentHash: '0x83ffb245cfced97ccc5c75253d6960376d6c6dea93647397a543a72fdaea5265', + miner: '0xdcc6960376d6c6dea93647383ffb245cfced97cf', + stateRoot: '0x54dda68af07643f68739a6e9612ad157a26ae7e2ce81f77842bb5835fbcde583', + sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', + bloom: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265', difficulty: new BigNumber(1000), totalDifficulty: new BigNumber(1000), number: 1000, gasLimit: 1000, gasUsed: 1000, timestamp: 1000, - extraData: '0x34234kjh23kj4234', - nonce: '0x34234kjh23kj4234', - children: ['0x34234kjh23kj4234'], + extraData: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265', + nonce: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265', + size: 1000 + }); + }); + it('should return the correct value, when null values are present', function () { + + assert.deepEqual(formatters.outputBlockFormatter({ + hash: null, + parentHash: '0x83ffb245cfced97ccc5c75253d6960376d6c6dea93647397a543a72fdaea5265', + miner: null, + stateRoot: '0x54dda68af07643f68739a6e9612ad157a26ae7e2ce81f77842bb5835fbcde583', + sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', + bloom: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265', + difficulty: '0x3e8', + totalDifficulty: '0x3e8', + number: null, + gasLimit: '0x3e8', + gasUsed: '0x3e8', + timestamp: '0x3e8', + extraData: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265', + nonce: null, + size: '0x3e8' + }), { + hash: null, + parentHash: '0x83ffb245cfced97ccc5c75253d6960376d6c6dea93647397a543a72fdaea5265', + miner: null, + stateRoot: '0x54dda68af07643f68739a6e9612ad157a26ae7e2ce81f77842bb5835fbcde583', + sha3Uncles: '0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347', + bloom: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265', + difficulty: new BigNumber(1000), + totalDifficulty: new BigNumber(1000), + number: null, + gasLimit: 1000, + gasUsed: 1000, + timestamp: 1000, + extraData: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265', + nonce: null, size: 1000 }); }); diff --git a/libjsqrc/ethereumjs/test/formatters.outputLogFormatter.js b/libjsqrc/ethereumjs/test/formatters.outputLogFormatter.js index 495a64620..432bfb0d2 100644 --- a/libjsqrc/ethereumjs/test/formatters.outputLogFormatter.js +++ b/libjsqrc/ethereumjs/test/formatters.outputLogFormatter.js @@ -9,17 +9,37 @@ describe('formatters', function () { transactionIndex: '0x3e8', logIndex: '0x3e8', blockNumber: '0x3e8', - transactionHash: '0x7b2274657374223a2274657374227d', - blockHash: '0x7b2274657374223a2274657374227d', - data: '0x7b2274657374223a2274657374227d', + transactionHash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265', + blockHash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265', + data: '0x7b2274657374223a2274657374227', topics: ['0x68656c6c6f','0x6d79746f70696373'] }), { transactionIndex: 1000, logIndex: 1000, blockNumber: 1000, - transactionHash: '0x7b2274657374223a2274657374227d', - blockHash: '0x7b2274657374223a2274657374227d', - data: '0x7b2274657374223a2274657374227d', + transactionHash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265', + blockHash: '0xd6960376d6c6dea93647383ffb245cfced97ccc5c7525397a543a72fdaea5265', + data: '0x7b2274657374223a2274657374227', + topics: ['0x68656c6c6f','0x6d79746f70696373'] + }); + }); + it('should return the correct value, when null values are present', function () { + + assert.deepEqual(formatters.outputLogFormatter({ + transactionIndex: null, + logIndex: null, + blockNumber: null, + transactionHash: null, + blockHash: null, + data: '0x7b2274657374223a2274657374227', + topics: ['0x68656c6c6f','0x6d79746f70696373'] + }), { + transactionIndex: null, + logIndex: null, + blockNumber: null, + transactionHash: null, + blockHash: null, + data: '0x7b2274657374223a2274657374227', topics: ['0x68656c6c6f','0x6d79746f70696373'] }); }); diff --git a/libjsqrc/ethereumjs/test/formatters.outputTransactionFormatter.js b/libjsqrc/ethereumjs/test/formatters.outputTransactionFormatter.js index ef19b6da7..db4831602 100644 --- a/libjsqrc/ethereumjs/test/formatters.outputTransactionFormatter.js +++ b/libjsqrc/ethereumjs/test/formatters.outputTransactionFormatter.js @@ -7,7 +7,7 @@ describe('formatters', function () { it('should return the correct value', function () { assert.deepEqual(formatters.outputTransactionFormatter({ - input: '0x34234kjh23kj4234', + input: '0x3454645634534', from: '0x00000', to: '0x00000', value: '0x3e8', @@ -16,9 +16,9 @@ describe('formatters', function () { nonce: '0xb', transactionIndex: '0x1', blockNumber: '0x3e8', - blockHash: '0x34234bf23bf4234' + blockHash: '0xc9b9cdc2092a9d6589d96662b1fd6949611163fb3910cf8a173cd060f17702f9' }), { - input: '0x34234kjh23kj4234', + input: '0x3454645634534', from: '0x00000', to: '0x00000', value: new BigNumber(1000), @@ -26,9 +26,36 @@ describe('formatters', function () { gasPrice: new BigNumber(1000), nonce: 11, blockNumber: 1000, - blockHash: '0x34234bf23bf4234', + blockHash: '0xc9b9cdc2092a9d6589d96662b1fd6949611163fb3910cf8a173cd060f17702f9', transactionIndex: 1 }); }); + + it('should return the correct value, when null values are present', function () { + + assert.deepEqual(formatters.outputTransactionFormatter({ + input: '0x3454645634534', + from: '0x00000', + to: null, + value: '0x3e8', + gas: '0x3e8', + gasPrice: '0x3e8', + nonce: '0xb', + transactionIndex: null, + blockNumber: null, + blockHash: null + }), { + input: '0x3454645634534', + from: '0x00000', + to: null, + value: new BigNumber(1000), + gas: 1000, + gasPrice: new BigNumber(1000), + nonce: 11, + blockNumber: null, + blockHash: null, + transactionIndex: null + }); + }); }); }); diff --git a/libjsqrc/ethereumjs/test/helpers/FakeHttpProvider2.js b/libjsqrc/ethereumjs/test/helpers/FakeHttpProvider2.js index 0f26d84b7..e287a0745 100644 --- a/libjsqrc/ethereumjs/test/helpers/FakeHttpProvider2.js +++ b/libjsqrc/ethereumjs/test/helpers/FakeHttpProvider2.js @@ -15,11 +15,21 @@ FakeHttpProvider2.prototype.injectResultList = function (list) { FakeHttpProvider2.prototype.getResponse = function () { var result = this.resultList[this.counter]; this.counter++; + + // add fallback result value + if(!result) + result = { + result: undefined + }; + if (result.type === 'batch') { this.injectBatchResults(result.result); } else { this.injectResult(result.result); } + + this.counter = 0; + return this.response; }; diff --git a/libjsqrc/ethereumjs/test/helpers/FakeXMLHttpRequest.js b/libjsqrc/ethereumjs/test/helpers/FakeXMLHttpRequest.js index a67d7f74a..6dc35b98a 100644 --- a/libjsqrc/ethereumjs/test/helpers/FakeXMLHttpRequest.js +++ b/libjsqrc/ethereumjs/test/helpers/FakeXMLHttpRequest.js @@ -6,6 +6,9 @@ var FakeXMLHttpRequest = function () { this.readyState = 4; this.onreadystatechange = null; this.async = false; + this.headers = { + 'Content-Type': 'text/plain' + }; }; FakeXMLHttpRequest.prototype.open = function (method, host, async) { @@ -15,6 +18,10 @@ FakeXMLHttpRequest.prototype.open = function (method, host, async) { this.async = async; }; +FakeXMLHttpRequest.prototype.setRequestHeader = function(name, value) { + this.headers[name] = value; +}; + FakeXMLHttpRequest.prototype.send = function (payload) { assert.equal(typeof payload, 'string'); if (this.async) { diff --git a/libjsqrc/ethereumjs/test/web3.extend.js b/libjsqrc/ethereumjs/test/web3.extend.js new file mode 100644 index 000000000..dfa863a23 --- /dev/null +++ b/libjsqrc/ethereumjs/test/web3.extend.js @@ -0,0 +1,76 @@ +var chai = require('chai'); +var assert = chai.assert; +var FakeHttpProvider = require('./helpers/FakeHttpProvider'); +var web3 = require('../lib/web3'); + + +var tests = [{ + properties: [new web3._extend.Property({ + name: 'gasPrice', + getter: 'eth_gasPrice', + outputFormatter: web3._extend.formatters.outputBigNumberFormatter + })] +},{ + methods: [new web3._extend.Method({ + name: 'getBalance', + call: 'eth_getBalance', + params: 2, + inputFormatter: [web3._extend.utils.toAddress, web3._extend.formatters.inputDefaultBlockNumberFormatter], + outputFormatter: web3._extend.formatters.outputBigNumberFormatter + })] +},{ + property: 'admin', + properties: [new web3._extend.Property({ + name: 'gasPrice', + getter: 'eth_gasPrice', + outputFormatter: web3._extend.formatters.outputBigNumberFormatter + })], + methods: [new web3._extend.Method({ + name: 'getBalance', + call: 'eth_getBalance', + params: 2, + inputFormatter: [web3._extend.utils.toAddress, web3._extend.formatters.inputDefaultBlockNumberFormatter], + outputFormatter: web3._extend.formatters.outputBigNumberFormatter + })] +}]; + +describe('web3', function () { + describe('_extend', function () { + tests.forEach(function (test, index) { + it('test no: ' + index, function () { + web3._extend(test); + + + if(test.properties) + test.properties.forEach(function(property){ + + var provider = new FakeHttpProvider(); + web3.setProvider(provider); + provider.injectResult(''); + provider.injectValidation(function (payload) { + assert.equal(payload.jsonrpc, '2.0'); + assert.equal(payload.method, property.getter); + }); + + if(test.property) { + assert.isObject(web3[test.property][property.name]); + assert.isFunction(web3[test.property]['get'+ property.name.charAt(0).toUpperCase() + property.name.slice(1)]); + } else { + assert.isObject(web3[property.name]); + assert.isFunction(web3['get'+ property.name.charAt(0).toUpperCase() + property.name.slice(1)]); + } + }); + + if(test.methods) + test.methods.forEach(function(property){ + if(test.property) + assert.isFunction(web3[test.property][property.name]); + else + assert.isFunction(web3[property.name]); + }); + + }); + }); + }); +}); + diff --git a/libjsqrc/js.qrc b/libjsqrc/js.qrc index 0fde5703a..8bdde07a3 100644 --- a/libjsqrc/js.qrc +++ b/libjsqrc/js.qrc @@ -2,6 +2,7 @@ bignumber.min.js setup.js + admin.js ethereumjs/dist/web3.js diff --git a/libp2p/CMakeLists.txt b/libp2p/CMakeLists.txt index 24a3116b6..335517f11 100644 --- a/libp2p/CMakeLists.txt +++ b/libp2p/CMakeLists.txt @@ -14,7 +14,7 @@ aux_source_directory(. SRC_LIST) include_directories(BEFORE ..) # we may not use it in libp2p, but one of our dependecies is including leveldb in header file # and windows is failing to build without that -include_directories(${LEVELDB_INCLUDE_DIRS}) +include_directories(${DB_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS}) if (MINIUPNPC_FOUND) diff --git a/libp2p/Capability.cpp b/libp2p/Capability.cpp index bc4aa0b04..2b8e6be63 100644 --- a/libp2p/Capability.cpp +++ b/libp2p/Capability.cpp @@ -28,14 +28,14 @@ using namespace std; using namespace dev; using namespace dev::p2p; -Capability::Capability(Session* _s, HostCapabilityFace* _h, unsigned _idOffset): m_session(_s), m_hostCap(_h), m_idOffset(_idOffset) +Capability::Capability(std::shared_ptr _s, HostCapabilityFace* _h, unsigned _idOffset): m_session(_s), m_hostCap(_h), m_idOffset(_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_hostCap->name() << "'. Reason:" << _problem; + clog(NetNote) << "DISABLE: Disabling capability '" << m_hostCap->name() << "'. Reason:" << _problem; m_enabled = false; } @@ -46,12 +46,16 @@ RLPStream& Capability::prep(RLPStream& _s, unsigned _id, unsigned _args) void Capability::sealAndSend(RLPStream& _s) { - m_session->sealAndSend(_s); + shared_ptr session = m_session.lock(); + if (session) + session->sealAndSend(_s); } void Capability::addRating(int _r) { - m_session->addRating(_r); + shared_ptr session = m_session.lock(); + if (session) + session->addRating(_r); } ReputationManager& Capability::repMan() const diff --git a/libp2p/Capability.h b/libp2p/Capability.h index b4f59b243..e54925621 100644 --- a/libp2p/Capability.h +++ b/libp2p/Capability.h @@ -31,12 +31,12 @@ namespace p2p class ReputationManager; -class Capability +class Capability: public std::enable_shared_from_this { friend class Session; public: - Capability(Session* _s, HostCapabilityFace* _h, unsigned _idOffset); + Capability(std::shared_ptr _s, HostCapabilityFace* _h, unsigned _idOffset); virtual ~Capability() {} // Implement these in the derived class. @@ -44,7 +44,7 @@ public: static u256 version() { return 0; } static unsigned messageCount() { return 0; } */ - Session* session() const { return m_session; } + std::shared_ptr session() const { return m_session.lock(); } HostCapabilityFace* hostCapability() const { return m_hostCap; } Host* host() const { return m_hostCap->host(); } ReputationManager& repMan() const; @@ -59,7 +59,7 @@ protected: void addRating(int _r); private: - Session* m_session; + std::weak_ptr m_session; HostCapabilityFace* m_hostCap; bool m_enabled = true; unsigned m_idOffset; diff --git a/libp2p/Host.cpp b/libp2p/Host.cpp index c9c2743ee..f033298ef 100644 --- a/libp2p/Host.cpp +++ b/libp2p/Host.cpp @@ -284,7 +284,7 @@ void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameCoder* for (auto const& i: caps) if (haveCapability(i)) { - ps->m_capabilities[i] = shared_ptr(m_capabilities[i]->newPeerCapability(ps.get(), o, i)); + ps->m_capabilities[i] = shared_ptr(m_capabilities[i]->newPeerCapability(ps, o, i)); o += m_capabilities[i]->messageCount(); } ps->start(); @@ -580,7 +580,8 @@ PeerSessionInfos Host::peerSessionInfo() const for (auto& i: m_sessions) if (auto j = i.second.lock()) if (j->isConnected()) - ret.push_back(j->m_info); + DEV_GUARDED(j->x_info) + ret.push_back(j->m_info); return ret; } diff --git a/libp2p/HostCapability.h b/libp2p/HostCapability.h index 48403bfdf..7032e31cb 100644 --- a/libp2p/HostCapability.h +++ b/libp2p/HostCapability.h @@ -53,7 +53,7 @@ protected: virtual u256 version() const = 0; CapDesc capDesc() const { return std::make_pair(name(), version()); } virtual unsigned messageCount() const = 0; - virtual Capability* newPeerCapability(Session* _s, unsigned _idOffset, CapDesc const& _cap) = 0; + virtual Capability* newPeerCapability(std::shared_ptr _s, unsigned _idOffset, CapDesc const& _cap) = 0; virtual void onStarting() {} virtual void onStopping() {} @@ -77,7 +77,7 @@ protected: virtual std::string name() const { return PeerCap::name(); } virtual u256 version() const { return PeerCap::version(); } virtual unsigned messageCount() const { return PeerCap::messageCount(); } - virtual Capability* newPeerCapability(Session* _s, unsigned _idOffset, CapDesc const& _cap) { return new PeerCap(_s, this, _idOffset, _cap); } + virtual Capability* newPeerCapability(std::shared_ptr _s, unsigned _idOffset, CapDesc const& _cap) { return new PeerCap(_s, this, _idOffset, _cap); } }; } diff --git a/libp2p/Session.cpp b/libp2p/Session.cpp index f24377fb2..1268b865c 100644 --- a/libp2p/Session.cpp +++ b/libp2p/Session.cpp @@ -43,7 +43,8 @@ Session::Session(Host* _h, RLPXFrameCoder* _io, std::shared_ptr cons { m_peer->m_lastDisconnect = NoDisconnect; m_lastReceived = m_connect = chrono::steady_clock::now(); - m_info.socketId = m_socket->ref().native_handle(); + DEV_GUARDED(x_info) + m_info.socketId = m_socket->ref().native_handle(); } Session::~Session() @@ -210,68 +211,14 @@ bool Session::interpret(PacketType _t, RLP const& _r) break; } case PongPacket: - m_info.lastPing = std::chrono::steady_clock::now() - m_ping; - clog(NetTriviaSummary) << "Latency: " << chrono::duration_cast(m_info.lastPing).count() << " ms"; + DEV_GUARDED(x_info) + { + m_info.lastPing = std::chrono::steady_clock::now() - m_ping; + clog(NetTriviaSummary) << "Latency: " << chrono::duration_cast(m_info.lastPing).count() << " ms"; + } break; case GetPeersPacket: - // Disabled for interop testing. - // GetPeers/PeersPacket will be modified to only exchange new nodes which it's peers are interested in. - break; - - clog(NetTriviaSummary) << "GetPeers"; - m_theyRequestedNodes = true; - serviceNodesRequest(); - break; case PeersPacket: - // Disabled for interop testing. - // GetPeers/PeersPacket will be modified to only exchange new nodes which it's peers are interested in. - break; - - clog(NetTriviaSummary) << "Peers (" << dec << (_r.itemCount() - 1) << " entries)"; - m_weRequestedNodes = false; - for (unsigned i = 0; i < _r.itemCount(); ++i) - { - bi::address peerAddress; - if (_r[i][0].size() == 16) - peerAddress = bi::address_v6(_r[i][0].toHash>().asArray()); - else if (_r[i][0].size() == 4) - peerAddress = bi::address_v4(_r[i][0].toHash>().asArray()); - else - { - cwarn << "Received bad peer packet:" << _r; - disconnect(BadProtocol); - return true; - } - auto ep = bi::tcp::endpoint(peerAddress, _r[i][1].toInt()); - NodeId id = _r[i][2].toHash(); - - clog(NetAllDetail) << "Checking: " << ep << "(" << id << ")"; - - if (!isPublicAddress(peerAddress)) - goto CONTINUE; // Private address. Ignore. - - if (!id) - goto LAMEPEER; // Null identity. Ignore. - - if (m_server->id() == id) - goto LAMEPEER; // Just our info - we already have that. - - if (id == this->id()) - goto LAMEPEER; // Just their info - we already have that. - - if (!ep.port()) - goto LAMEPEER; // Zero port? Don't think so. - - if (ep.port() >= /*49152*/32768) - goto LAMEPEER; // Private port according to IANA. - - // OK passed all our checks. Assume it's good. - addRating(1000); - m_server->addNode(id, NodeIPEndpoint(ep.address(), ep.port(), ep.port())); - clog(NetTriviaDetail) << "New peer: " << ep << "(" << id << ")"; - CONTINUE:; - LAMEPEER:; - } break; default: return false; @@ -387,11 +334,12 @@ void Session::drop(DisconnectReason _reason) void Session::disconnect(DisconnectReason _reason) { clog(NetConnect) << "Disconnecting (our reason:" << reasonOf(_reason) << ")"; - StructuredLogger::p2pDisconnected( - m_info.id.abridged(), - m_peer->endpoint, // TODO: may not be 100% accurate - m_server->peerCount() - ); + DEV_GUARDED(x_info) + StructuredLogger::p2pDisconnected( + m_info.id.abridged(), + m_peer->endpoint, // TODO: may not be 100% accurate + m_server->peerCount() + ); if (m_socket->ref().is_open()) { RLPStream s; diff --git a/libp2p/Session.h b/libp2p/Session.h index ba46c5a16..0a55b2653 100644 --- a/libp2p/Session.h +++ b/libp2p/Session.h @@ -67,7 +67,7 @@ public: bool isConnected() const { return m_socket->ref().is_open(); } NodeId id() const; - unsigned socketId() const { return m_info.socketId; } + unsigned socketId() const { Guard l(x_info); return m_info.socketId; } template std::shared_ptr cap() const { try { return std::static_pointer_cast(m_capabilities.at(std::make_pair(PeerCap::name(), PeerCap::version()))); } catch (...) { return nullptr; } } @@ -81,9 +81,9 @@ public: int rating() const; void addRating(int _r); - void addNote(std::string const& _k, std::string const& _v) { m_info.notes[_k] = _v; } + void addNote(std::string const& _k, std::string const& _v) { Guard l(x_info); m_info.notes[_k] = _v; } - PeerSessionInfo const& info() const { return m_info; } + PeerSessionInfo info() const { Guard l(x_info); return m_info; } void ensureNodesRequested(); void serviceNodesRequest(); @@ -125,6 +125,7 @@ private: std::shared_ptr m_peer; ///< The Peer object. bool m_dropped = false; ///< If true, we've already divested ourselves of this peer. We're just waiting for the reads & writes to fail before the shared_ptr goes OOS and the destructor kicks in. + mutable Mutex x_info; PeerSessionInfo m_info; ///< Dynamic information about this peer. bool m_theyRequestedNodes = false; ///< Has the peer requested nodes from us without receiveing an answer from us? diff --git a/libsolidity/ArrayUtils.cpp b/libsolidity/ArrayUtils.cpp index 43ffff0b6..3be12af72 100644 --- a/libsolidity/ArrayUtils.cpp +++ b/libsolidity/ArrayUtils.cpp @@ -39,11 +39,6 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons // stack layout: [source_ref] [source_byte_off] [source length] target_ref target_byte_off (top) solAssert(_targetType.location() == DataLocation::Storage, ""); - solAssert( - _sourceType.location() == DataLocation::CallData || - _sourceType.location() == DataLocation::Storage, - "Given array location not implemented." - ); IntegerType uint256(256); Type const* targetBaseType = _targetType.isByteArray() ? &uint256 : &(*_targetType.getBaseType()); @@ -52,6 +47,7 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons // TODO unroll loop for small sizes bool sourceIsStorage = _sourceType.location() == DataLocation::Storage; + bool fromCalldata = _sourceType.location() == DataLocation::CallData; bool directCopy = sourceIsStorage && sourceBaseType->isValueType() && *sourceBaseType == *targetBaseType; bool haveByteOffsetSource = !directCopy && sourceIsStorage && sourceBaseType->getStorageBytes() <= 16; bool haveByteOffsetTarget = !directCopy && targetBaseType->getStorageBytes() <= 16; @@ -71,6 +67,13 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons // retrieve source length if (_sourceType.location() != DataLocation::CallData || !_sourceType.isDynamicallySized()) retrieveLength(_sourceType); // otherwise, length is already there + if (_sourceType.location() == DataLocation::Memory && _sourceType.isDynamicallySized()) + { + // increment source pointer to point to data + m_context << eth::Instruction::SWAP1 << u256(0x20); + m_context << eth::Instruction::ADD << eth::Instruction::SWAP1; + } + // stack: target_ref source_ref source_length m_context << eth::Instruction::DUP3; // stack: target_ref source_ref source_length target_ref @@ -164,9 +167,9 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons StorageItem(m_context, *sourceBaseType).retrieveValue(SourceLocation(), true); } else if (sourceBaseType->isValueType()) - CompilerUtils(m_context).loadFromMemoryDynamic(*sourceBaseType, true, true, false); + CompilerUtils(m_context).loadFromMemoryDynamic(*sourceBaseType, fromCalldata, true, false); else - solAssert(false, "Copying of unknown type requested: " + sourceBaseType->toString()); + solAssert(false, "Copying of type " + _sourceType.toString(false) + " to storage not yet supported."); // stack: target_ref target_data_end source_data_pos target_data_pos source_data_end [target_byte_offset] [source_byte_offset] ... solAssert( 2 + byteOffsetSize + sourceBaseType->getSizeOnStack() <= 16, @@ -228,6 +231,181 @@ void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType cons m_context << u256(0); } +void ArrayUtils::copyArrayToMemory(const ArrayType& _sourceType, bool _padToWordBoundaries) const +{ + solAssert( + _sourceType.getBaseType()->getCalldataEncodedSize() > 0, + "Nested arrays not yet implemented here." + ); + unsigned baseSize = 1; + if (!_sourceType.isByteArray()) + // We always pad the elements, regardless of _padToWordBoundaries. + baseSize = _sourceType.getBaseType()->getCalldataEncodedSize(); + + if (_sourceType.location() == DataLocation::CallData) + { + if (!_sourceType.isDynamicallySized()) + m_context << _sourceType.getLength(); + if (_sourceType.getBaseType()->getCalldataEncodedSize() > 1) + m_context << u256(baseSize) << eth::Instruction::MUL; + // stack: target source_offset source_len + m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 << eth::Instruction::DUP5; + // stack: target source_offset source_len source_len source_offset target + m_context << eth::Instruction::CALLDATACOPY; + m_context << eth::Instruction::DUP3 << eth::Instruction::ADD; + m_context << eth::Instruction::SWAP2 << eth::Instruction::POP << eth::Instruction::POP; + } + else if (_sourceType.location() == DataLocation::Memory) + { + // memcpy using the built-in contract + retrieveLength(_sourceType); + if (_sourceType.isDynamicallySized()) + { + // change pointer to data part + m_context << eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD; + m_context << eth::Instruction::SWAP1; + } + // convert length to size + if (baseSize > 1) + m_context << u256(baseSize) << eth::Instruction::MUL; + // stack: + //@TODO do not use ::CALL if less than 32 bytes? + m_context << eth::Instruction::DUP1 << eth::Instruction::DUP4 << eth::Instruction::DUP4; + CompilerUtils(m_context).memoryCopy(); + + m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; + // stack: + + bool paddingNeeded = false; + if (_sourceType.isDynamicallySized()) + paddingNeeded = _padToWordBoundaries && ((baseSize % 32) != 0); + else + paddingNeeded = _padToWordBoundaries && (((_sourceType.getLength() * baseSize) % 32) != 0); + if (paddingNeeded) + { + // stack: + m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2 << eth::Instruction::ADD; + // stack: + m_context << eth::Instruction::SWAP1 << u256(31) << eth::Instruction::AND; + // stack: + eth::AssemblyItem skip = m_context.newTag(); + if (_sourceType.isDynamicallySized()) + { + m_context << eth::Instruction::DUP1 << eth::Instruction::ISZERO; + m_context.appendConditionalJumpTo(skip); + } + // round off, load from there. + // stack + m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3; + m_context << eth::Instruction::SUB; + // stack: target+size remainder + m_context << eth::Instruction::DUP1 << eth::Instruction::MLOAD; + // Now we AND it with ~(2**(8 * (32 - remainder)) - 1) + m_context << u256(1); + m_context << eth::Instruction::DUP4 << u256(32) << eth::Instruction::SUB; + // stack: ... 1 <32 - remainder> + m_context << u256(0x100) << eth::Instruction::EXP << eth::Instruction::SUB; + m_context << eth::Instruction::NOT << eth::Instruction::AND; + // stack: target+size remainder target+size-remainder + m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE; + // stack: target+size remainder target+size-remainder + m_context << u256(32) << eth::Instruction::ADD; + // stack: target+size remainder + m_context << eth::Instruction::SWAP2 << eth::Instruction::POP; + + if (_sourceType.isDynamicallySized()) + m_context << skip.tag(); + // stack + m_context << eth::Instruction::POP; + } + else + // stack: + m_context << eth::Instruction::ADD; + } + else + { + solAssert(_sourceType.location() == DataLocation::Storage, ""); + unsigned storageBytes = _sourceType.getBaseType()->getStorageBytes(); + u256 storageSize = _sourceType.getBaseType()->getStorageSize(); + solAssert(storageSize > 1 || (storageSize == 1 && storageBytes > 0), ""); + + m_context << eth::Instruction::POP; // remove offset, arrays always start new slot + retrieveLength(_sourceType); + // stack here: memory_offset storage_offset length + // jump to end if length is zero + m_context << eth::Instruction::DUP1 << eth::Instruction::ISZERO; + eth::AssemblyItem loopEnd = m_context.newTag(); + m_context.appendConditionalJumpTo(loopEnd); + // compute memory end offset + if (baseSize > 1) + // convert length to memory size + m_context << u256(baseSize) << eth::Instruction::MUL; + m_context << eth::Instruction::DUP3 << eth::Instruction::ADD << eth::Instruction::SWAP2; + if (_sourceType.isDynamicallySized()) + { + // actual array data is stored at SHA3(storage_offset) + m_context << eth::Instruction::SWAP1; + CompilerUtils(m_context).computeHashStatic(); + m_context << eth::Instruction::SWAP1; + } + + // stack here: memory_end_offset storage_data_offset memory_offset + bool haveByteOffset = !_sourceType.isByteArray() && storageBytes <= 16; + if (haveByteOffset) + m_context << u256(0) << eth::Instruction::SWAP1; + // stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset + eth::AssemblyItem loopStart = m_context.newTag(); + m_context << loopStart; + // load and store + if (_sourceType.isByteArray()) + { + // Packed both in storage and memory. + m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD; + m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE; + // increment storage_data_offset by 1 + m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::ADD; + // increment memory offset by 32 + m_context << eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD; + } + else + { + // stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset + if (haveByteOffset) + m_context << eth::Instruction::DUP3 << eth::Instruction::DUP3; + else + m_context << eth::Instruction::DUP2 << u256(0); + StorageItem(m_context, *_sourceType.getBaseType()).retrieveValue(SourceLocation(), true); + CompilerUtils(m_context).storeInMemoryDynamic(*_sourceType.getBaseType()); + // increment storage_data_offset and byte offset + if (haveByteOffset) + incrementByteOffset(storageBytes, 2, 3); + else + { + m_context << eth::Instruction::SWAP1; + m_context << storageSize << eth::Instruction::ADD; + m_context << eth::Instruction::SWAP1; + } + } + // check for loop condition + m_context << eth::Instruction::DUP1 << eth::dupInstruction(haveByteOffset ? 5 : 4) << eth::Instruction::GT; + m_context.appendConditionalJumpTo(loopStart); + // stack here: memory_end_offset storage_data_offset [storage_byte_offset] memory_offset + if (haveByteOffset) + m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; + if (_padToWordBoundaries && baseSize % 32 != 0) + { + // memory_end_offset - start is the actual length (we want to compute the ceil of). + // memory_offset - start is its next multiple of 32, but it might be off by 32. + // so we compute: memory_end_offset += (memory_offset - memory_end_offest) & 31 + m_context << eth::Instruction::DUP3 << eth::Instruction::SWAP1 << eth::Instruction::SUB; + m_context << u256(31) << eth::Instruction::AND; + m_context << eth::Instruction::DUP3 << eth::Instruction::ADD; + m_context << eth::Instruction::SWAP2; + } + m_context << loopEnd << eth::Instruction::POP << eth::Instruction::POP; + } +} + void ArrayUtils::clearArray(ArrayType const& _type) const { unsigned stackHeightStart = m_context.getStackHeight(); @@ -419,6 +597,10 @@ void ArrayUtils::convertLengthToSize(ArrayType const& _arrayType, bool _pad) con } else { + solAssert( + _arrayType.getBaseType()->getCalldataEncodedSize() > 0, + "Copying nested dynamic arrays not yet implemented." + ); if (!_arrayType.isByteArray()) m_context << _arrayType.getBaseType()->getCalldataEncodedSize() << eth::Instruction::MUL; else if (_pad) @@ -485,16 +667,19 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType) const switch (location) { case DataLocation::CallData: + case DataLocation::Memory: if (!_arrayType.isByteArray()) { m_context << eth::Instruction::SWAP1; m_context << _arrayType.getBaseType()->getCalldataEncodedSize() << eth::Instruction::MUL; } m_context << eth::Instruction::ADD; + //@todo we should also load if it is a reference type of dynamic length + // but we should apply special logic if we load from calldata. if (_arrayType.getBaseType()->isValueType()) CompilerUtils(m_context).loadFromMemoryDynamic( *_arrayType.getBaseType(), - true, + location == DataLocation::CallData, !_arrayType.isByteArray(), false ); @@ -527,8 +712,6 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType) const m_context << eth::Instruction::ADD << u256(0); } break; - case DataLocation::Memory: - solAssert(false, "Memory lvalues not yet implemented."); } } diff --git a/libsolidity/ArrayUtils.h b/libsolidity/ArrayUtils.h index dab40e2d6..8d56f3c8f 100644 --- a/libsolidity/ArrayUtils.h +++ b/libsolidity/ArrayUtils.h @@ -44,6 +44,10 @@ public: /// Stack pre: source_reference [source_byte_offset/source_length] target_reference target_byte_offset /// Stack post: target_reference target_byte_offset void copyArrayToStorage(ArrayType const& _targetType, ArrayType const& _sourceType) const; + /// Copies an array (which cannot be dynamically nested) from anywhere to memory. + /// Stack pre: memory_offset source_item + /// Stack post: memory_offest + length(padded) + void copyArrayToMemory(ArrayType const& _sourceType, bool _padToWordBoundaries = true) const; /// Clears the given dynamic or static array. /// Stack pre: storage_ref storage_byte_offset /// Stack post: diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index 0b88ed8ae..b05a7a9b1 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -163,14 +163,30 @@ void Compiler::appendConstructor(FunctionDefinition const& _constructor) { CompilerContext::LocationSetter locationSetter(m_context, _constructor); // copy constructor arguments from code to memory and then to stack, they are supplied after the actual program - unsigned argumentSize = 0; - for (ASTPointer const& var: _constructor.getParameters()) - argumentSize += var->getType()->getCalldataEncodedSize(); - - if (argumentSize > 0) + if (!_constructor.getParameters().empty()) { + unsigned argumentSize = 0; + for (ASTPointer const& var: _constructor.getParameters()) + if (var->getType()->isDynamicallySized()) + { + argumentSize = 0; + break; + } + else + argumentSize += var->getType()->getCalldataEncodedSize(); + CompilerUtils(m_context).fetchFreeMemoryPointer(); - m_context << u256(argumentSize) << eth::Instruction::DUP1; + if (argumentSize == 0) + { + // argument size is dynamic, use CODESIZE to determine it + m_context.appendProgramSize(); // program itself + // CODESIZE is program plus manually added arguments + m_context << eth::Instruction::CODESIZE << eth::Instruction::SUB; + } + else + m_context << u256(argumentSize); + // stack: + m_context << eth::Instruction::DUP1; m_context.appendProgramSize(); m_context << eth::Instruction::DUP4 << eth::Instruction::CODECOPY; m_context << eth::Instruction::ADD; @@ -265,8 +281,9 @@ void Compiler::appendCalldataUnpacker( { solAssert(arrayType.location() == DataLocation::Memory, ""); // compute data pointer + m_context << eth::Instruction::DUP1 << eth::Instruction::MLOAD; //@todo once we support nested arrays, this offset needs to be dynamic. - m_context << eth::Instruction::DUP1 << _startOffset << eth::Instruction::ADD; + m_context << _startOffset << eth::Instruction::ADD; m_context << eth::Instruction::SWAP1 << u256(0x20) << eth::Instruction::ADD; } else @@ -375,9 +392,9 @@ bool Compiler::visit(FunctionDefinition const& _function) } for (ASTPointer const& variable: _function.getReturnParameters()) - m_context.addAndInitializeVariable(*variable); + appendStackVariableInitialisation(*variable); for (VariableDeclaration const* localVariable: _function.getLocalVariables()) - m_context.addAndInitializeVariable(*localVariable); + appendStackVariableInitialisation(*localVariable); if (_function.isConstructor()) if (auto c = m_context.getNextConstructor(dynamic_cast(*_function.getScope()))) @@ -622,7 +639,7 @@ void Compiler::appendModifierOrFunctionCode() modifier.getParameters()[i]->getType()); } for (VariableDeclaration const* localVariable: modifier.getLocalVariables()) - m_context.addAndInitializeVariable(*localVariable); + appendStackVariableInitialisation(*localVariable); unsigned const c_stackSurplus = CompilerUtils::getSizeOnStack(modifier.getParameters()) + CompilerUtils::getSizeOnStack(modifier.getLocalVariables()); @@ -636,6 +653,13 @@ void Compiler::appendModifierOrFunctionCode() } } +void Compiler::appendStackVariableInitialisation(VariableDeclaration const& _variable) +{ + CompilerContext::LocationSetter location(m_context, _variable); + m_context.addVariable(_variable); + ExpressionCompiler(m_context).appendStackVariableInitialisation(*_variable.getType()); +} + void Compiler::compileExpression(Expression const& _expression, TypePointer const& _targetType) { ExpressionCompiler expressionCompiler(m_context, m_optimize); diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index 60ca00e83..ac794f89e 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -84,6 +84,13 @@ private: void registerStateVariables(ContractDefinition const& _contract); void initializeStateVariables(ContractDefinition const& _contract); + /// Initialises all memory arrays in the local variables to point to an empty location. + void initialiseMemoryArrays(std::vector _variables); + /// Pushes the initialised value of the given type to the stack. If the type is a memory + /// reference type, allocates memory and pushes the memory pointer. + /// Not to be used for storage references. + void initialiseInMemory(Type const& _type); + virtual bool visit(VariableDeclaration const& _variableDeclaration) override; virtual bool visit(FunctionDefinition const& _function) override; virtual bool visit(IfStatement const& _ifStatement) override; @@ -100,6 +107,7 @@ private: /// body itself if the last modifier was reached. void appendModifierOrFunctionCode(); + void appendStackVariableInitialisation(VariableDeclaration const& _variable); void compileExpression(Expression const& _expression, TypePointer const& _targetType = TypePointer()); bool const m_optimize; diff --git a/libsolidity/CompilerContext.cpp b/libsolidity/CompilerContext.cpp index fde6adacc..0f6f5fe76 100644 --- a/libsolidity/CompilerContext.cpp +++ b/libsolidity/CompilerContext.cpp @@ -65,15 +65,6 @@ void CompilerContext::removeVariable(VariableDeclaration const& _declaration) m_localVariables.erase(&_declaration); } -void CompilerContext::addAndInitializeVariable(VariableDeclaration const& _declaration) -{ - LocationSetter locationSetter(*this, _declaration); - addVariable(_declaration); - int const size = _declaration.getType()->getSizeOnStack(); - for (int i = 0; i < size; ++i) - *this << u256(0); -} - bytes const& CompilerContext::getCompiledContract(const ContractDefinition& _contract) const { auto ret = m_compiledContracts.find(&_contract); diff --git a/libsolidity/CompilerContext.h b/libsolidity/CompilerContext.h index 998b0a2f7..3f97d900b 100644 --- a/libsolidity/CompilerContext.h +++ b/libsolidity/CompilerContext.h @@ -46,7 +46,6 @@ public: void addStateVariable(VariableDeclaration const& _declaration, u256 const& _storageOffset, unsigned _byteOffset); void addVariable(VariableDeclaration const& _declaration, unsigned _offsetToCurrent = 0); void removeVariable(VariableDeclaration const& _declaration); - void addAndInitializeVariable(VariableDeclaration const& _declaration); void setCompiledContracts(std::map const& _contracts) { m_compiledContracts = _contracts; } bytes const& getCompiledContract(ContractDefinition const& _contract) const; diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp index 4d57dc926..47a9a3542 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/CompilerUtils.cpp @@ -25,6 +25,7 @@ #include #include #include +#include using namespace std; @@ -91,142 +92,20 @@ void CompilerUtils::loadFromMemoryDynamic( } } -unsigned CompilerUtils::storeInMemory(unsigned _offset, Type const& _type, bool _padToWordBoundaries) +void CompilerUtils::storeInMemory(unsigned _offset) { - solAssert(_type.getCategory() != Type::Category::Array, "Unable to statically store dynamic type."); - unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries); + unsigned numBytes = prepareMemoryStore(IntegerType(256), true); if (numBytes > 0) m_context << u256(_offset) << eth::Instruction::MSTORE; - return numBytes; } void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBoundaries) { if (_type.getCategory() == Type::Category::Array) - { - auto const& type = dynamic_cast(_type); - solAssert(type.isByteArray(), "Non byte arrays not yet implemented here."); - - if (type.location() == DataLocation::CallData) - { - if (!type.isDynamicallySized()) - m_context << type.getLength(); - // stack: target source_offset source_len - m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 << eth::Instruction::DUP5; - // stack: target source_offset source_len source_len source_offset target - m_context << eth::Instruction::CALLDATACOPY; - m_context << eth::Instruction::DUP3 << eth::Instruction::ADD; - m_context << eth::Instruction::SWAP2 << eth::Instruction::POP << eth::Instruction::POP; - } - else if (type.location() == DataLocation::Memory) - { - // memcpy using the built-in contract - ArrayUtils(m_context).retrieveLength(type); - if (type.isDynamicallySized()) - { - // change pointer to data part - m_context << eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD; - m_context << eth::Instruction::SWAP1; - } - // stack: - // stack for call: outsize target size source value contract gas - m_context << eth::Instruction::DUP1 << eth::Instruction::DUP4; - m_context << eth::Instruction::DUP2 << eth::Instruction::DUP5; - m_context << u256(0) << u256(identityContractAddress); - //@TODO do not use ::CALL if less than 32 bytes? - //@todo in production, we should not have to pair c_callNewAccountGas. - m_context << u256(eth::c_callGas + 10 + eth::c_callNewAccountGas) << eth::Instruction::GAS; - m_context << eth::Instruction::SUB << eth::Instruction::CALL; - m_context << eth::Instruction::POP; // ignore return value - - m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; - // stack: - - if (_padToWordBoundaries && (type.isDynamicallySized() || (type.getLength()) % 32 != 0)) - { - // stack: - m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2 << eth::Instruction::ADD; - // stack: - m_context << eth::Instruction::SWAP1 << u256(31) << eth::Instruction::AND; - // stack: - eth::AssemblyItem skip = m_context.newTag(); - if (type.isDynamicallySized()) - { - m_context << eth::Instruction::DUP1 << eth::Instruction::ISZERO; - m_context.appendConditionalJumpTo(skip); - } - // round off, load from there. - // stack - m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3; - m_context << eth::Instruction::SUB; - // stack: target+length remainder - m_context << eth::Instruction::DUP1 << eth::Instruction::MLOAD; - // Now we AND it with ~(2**(8 * (32 - remainder)) - 1) - m_context << u256(1); - m_context << eth::Instruction::DUP4 << u256(32) << eth::Instruction::SUB; - // stack: ... 1 <32 - remainder> - m_context << u256(0x100) << eth::Instruction::EXP << eth::Instruction::SUB; - m_context << eth::Instruction::NOT << eth::Instruction::AND; - // stack: target+length remainder target+length-remainder - m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE; - // stack: target+length remainder target+length-remainder - m_context << u256(32) << eth::Instruction::ADD; - // stack: target+length remainder - m_context << eth::Instruction::SWAP2 << eth::Instruction::POP; - - if (type.isDynamicallySized()) - m_context << skip.tag(); - // stack - m_context << eth::Instruction::POP; - } - else - // stack: - m_context << eth::Instruction::ADD; - } - else - { - solAssert(type.location() == DataLocation::Storage, ""); - m_context << eth::Instruction::POP; // remove offset, arrays always start new slot - m_context << eth::Instruction::DUP1 << eth::Instruction::SLOAD; - // stack here: memory_offset storage_offset length_bytes - // jump to end if length is zero - m_context << eth::Instruction::DUP1 << eth::Instruction::ISZERO; - eth::AssemblyItem loopEnd = m_context.newTag(); - m_context.appendConditionalJumpTo(loopEnd); - // compute memory end offset - m_context << eth::Instruction::DUP3 << eth::Instruction::ADD << eth::Instruction::SWAP2; - // actual array data is stored at SHA3(storage_offset) - m_context << eth::Instruction::SWAP1; - CompilerUtils(m_context).computeHashStatic(); - m_context << eth::Instruction::SWAP1; - - // stack here: memory_end_offset storage_data_offset memory_offset - eth::AssemblyItem loopStart = m_context.newTag(); - m_context << loopStart; - // load and store - m_context << eth::Instruction::DUP2 << eth::Instruction::SLOAD; - m_context << eth::Instruction::DUP2 << eth::Instruction::MSTORE; - // increment storage_data_offset by 1 - m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::ADD; - // increment memory offset by 32 - m_context << eth::Instruction::SWAP1 << u256(32) << eth::Instruction::ADD; - // check for loop condition - m_context << eth::Instruction::DUP1 << eth::Instruction::DUP4 << eth::Instruction::GT; - m_context.appendConditionalJumpTo(loopStart); - // stack here: memory_end_offset storage_data_offset memory_offset - if (_padToWordBoundaries) - { - // memory_end_offset - start is the actual length (we want to compute the ceil of). - // memory_offset - start is its next multiple of 32, but it might be off by 32. - // so we compute: memory_end_offset += (memory_offset - memory_end_offest) & 31 - m_context << eth::Instruction::DUP3 << eth::Instruction::SWAP1 << eth::Instruction::SUB; - m_context << u256(31) << eth::Instruction::AND; - m_context << eth::Instruction::DUP3 << eth::Instruction::ADD; - m_context << eth::Instruction::SWAP2; - } - m_context << loopEnd << eth::Instruction::POP << eth::Instruction::POP; - } - } + ArrayUtils(m_context).copyArrayToMemory( + dynamic_cast(_type), + _padToWordBoundaries + ); else { unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries); @@ -341,6 +220,21 @@ void CompilerUtils::encodeToMemory( popStackSlots(argSize + dynPointers + 1); } +void CompilerUtils::memoryCopy() +{ + // Stack here: size target source + // stack for call: outsize target size source value contract gas + //@TODO do not use ::CALL if less than 32 bytes? + m_context << eth::Instruction::DUP3 << eth::Instruction::SWAP1; + m_context << u256(0) << u256(identityContractAddress); + // compute gas costs + m_context << u256(32) << eth::Instruction::DUP5 << u256(31) << eth::Instruction::ADD; + m_context << eth::Instruction::DIV << u256(eth::c_identityWordGas) << eth::Instruction::MUL; + m_context << u256(eth::c_identityGas) << eth::Instruction::ADD; + m_context << eth::Instruction::CALL; + m_context << eth::Instruction::POP; // ignore return value +} + void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded) { // For a type extension, we need to remove all higher-order bits that we might have ignored in @@ -515,7 +409,14 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp break; } default: - solAssert(false, "Invalid type conversion requested."); + solAssert( + false, + "Invalid type conversion " + + _typeOnStack.toString(false) + + " to " + + _targetType.toString(false) + + " requested." + ); } break; } @@ -599,11 +500,10 @@ unsigned CompilerUtils::getSizeOnStack(vector> const& _va return size; } -void CompilerUtils::computeHashStatic(Type const& _type, bool _padToWordBoundaries) +void CompilerUtils::computeHashStatic() { - unsigned length = storeInMemory(0, _type, _padToWordBoundaries); - solAssert(length <= CompilerUtils::freeMemoryPointer, ""); - m_context << u256(length) << u256(0) << eth::Instruction::SHA3; + storeInMemory(0); + m_context << u256(32) << u256(0) << eth::Instruction::SHA3; } unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries) diff --git a/libsolidity/CompilerUtils.h b/libsolidity/CompilerUtils.h index a880f9ee4..a9e07f74f 100644 --- a/libsolidity/CompilerUtils.h +++ b/libsolidity/CompilerUtils.h @@ -65,18 +65,14 @@ public: bool _padToWordBoundaries = true, bool _keepUpdatedMemoryOffset = true ); - /// Stores data from stack in memory. + /// Stores a 256 bit integer from stack in memory. /// @param _offset offset in memory /// @param _type type of the data on the stack - /// @param _padToWordBoundaries if true, pad the data to word (32 byte) boundaries - /// @returns the number of bytes written to memory (can be different from _bytes if - /// _padToWordBoundaries is true) - unsigned storeInMemory(unsigned _offset, - Type const& _type = IntegerType(256), - bool _padToWordBoundaries = false - ); + void storeInMemory(unsigned _offset); /// Dynamic version of @see storeInMemory, expects the memory offset below the value on the stack /// and also updates that. For arrays, only copies the data part. + /// @param _padToWordBoundaries if true, adds zeros to pad to multiple of 32 bytes. Array elements + /// are always padded (except for byte arrays), regardless of this parameter. /// Stack pre: memory_offset value... /// Stack post: (memory_offset+length) void storeInMemoryDynamic(Type const& _type, bool _padToWordBoundaries = true); @@ -99,6 +95,11 @@ public: bool _copyDynamicDataInPlace = false ); + /// Uses a CALL to the identity contract to perform a memory-to-memory copy. + /// Stack pre: + /// Stack post: + void memoryCopy(); + /// Appends code for an implicit or explicit type conversion. This includes erasing higher /// order bits (@see appendHighBitCleanup) when widening integer but also copy to memory /// if a reference type is converted from calldata or storage to memory. @@ -124,10 +125,8 @@ public: static unsigned getSizeOnStack(std::vector const& _variables); static unsigned getSizeOnStack(std::vector> const& _variableTypes); - /// Appends code that computes tha SHA3 hash of the topmost stack element of type @a _type. - /// If @a _pad is set, padds the type to muliples of 32 bytes. - /// @note Only works for types of fixed size. - void computeHashStatic(Type const& _type = IntegerType(256), bool _padToWordBoundaries = false); + /// Appends code that computes tha SHA3 hash of the topmost stack element of 32 byte type. + void computeHashStatic(); /// Bytes we need to the start of call data. /// - The size in bytes of the function (hash) identifier. diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index bfb945d8f..fb10eb83b 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -56,6 +56,62 @@ void ExpressionCompiler::appendStateVariableInitialization(VariableDeclaration c StorageItem(m_context, _varDecl).storeValue(*_varDecl.getType(), _varDecl.getLocation(), true); } +void ExpressionCompiler::appendStackVariableInitialisation(Type const& _type, bool _toMemory) +{ + CompilerUtils utils(m_context); + auto const* referenceType = dynamic_cast(&_type); + if (!referenceType || referenceType->location() == DataLocation::Storage) + { + for (size_t i = 0; i < _type.getSizeOnStack(); ++i) + m_context << u256(0); + if (_toMemory) + utils.storeInMemoryDynamic(_type); + return; + } + solAssert(referenceType->location() == DataLocation::Memory, ""); + if (!_toMemory) + { + // allocate memory + utils.fetchFreeMemoryPointer(); + m_context << eth::Instruction::DUP1 << u256(max(32u, _type.getCalldataEncodedSize())); + m_context << eth::Instruction::ADD; + utils.storeFreeMemoryPointer(); + m_context << eth::Instruction::DUP1; + } + + if (auto structType = dynamic_cast(&_type)) + for (auto const& member: structType->getMembers()) + appendStackVariableInitialisation(*member.type, true); + else if (auto arrayType = dynamic_cast(&_type)) + { + if (arrayType->isDynamicallySized()) + { + // zero length + m_context << u256(0); + CompilerUtils(m_context).storeInMemoryDynamic(IntegerType(256)); + } + else if (arrayType->getLength() > 0) + { + m_context << arrayType->getLength() << eth::Instruction::SWAP1; + // stack: items_to_do memory_pos + auto repeat = m_context.newTag(); + m_context << repeat; + appendStackVariableInitialisation(*arrayType->getBaseType(), true); + m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::SWAP1; + m_context << eth::Instruction::SUB << eth::Instruction::SWAP1; + m_context << eth::Instruction::DUP2; + m_context.appendConditionalJumpTo(repeat); + m_context << eth::Instruction::SWAP1 << eth::Instruction::POP; + } + } + else + solAssert(false, "Requested initialisation for unknown type: " + _type.toString()); + + if (!_toMemory) + // remove the updated memory pointer + m_context << eth::Instruction::POP; +} + void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl) { CompilerContext::LocationSetter locationSetter(m_context, _varDecl); @@ -457,6 +513,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) strings(), Location::Bare, false, + nullptr, true, true ), @@ -724,8 +781,8 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) case DataLocation::Storage: setLValue(_memberAccess, type); break; - default: - solAssert(false, "Unsupported array location."); + case DataLocation::Memory: + m_context << eth::Instruction::MLOAD; break; } break; @@ -1004,9 +1061,14 @@ void ExpressionCompiler::appendExternalFunctionCall( _functionType.getReturnParameterTypes().empty() ? nullptr : _functionType.getReturnParameterTypes().front().get(); - unsigned retSize = firstReturnType ? firstReturnType->getCalldataEncodedSize() : 0; + unsigned retSize = 0; if (returnSuccessCondition) retSize = 0; // return value actually is success condition + else if (firstReturnType) + { + retSize = firstReturnType->getCalldataEncodedSize(); + solAssert(retSize > 0, "Unable to return dynamic type from external call."); + } // Evaluate arguments. TypePointers argumentTypes; @@ -1123,6 +1185,7 @@ void ExpressionCompiler::appendExternalFunctionCall( //@todo manually update free memory pointer if we accept returning memory-stored objects utils().fetchFreeMemoryPointer(); utils().loadFromMemoryDynamic(*firstReturnType, false, true, false); + } } diff --git a/libsolidity/ExpressionCompiler.h b/libsolidity/ExpressionCompiler.h index 642560c64..747e241ef 100644 --- a/libsolidity/ExpressionCompiler.h +++ b/libsolidity/ExpressionCompiler.h @@ -64,6 +64,13 @@ public: /// Appends code to set a state variable to its initial value/expression. void appendStateVariableInitialization(VariableDeclaration const& _varDecl); + /// Appends code to initialise a local variable. + /// If @a _toMemory is false, leaves the value on the stack. For memory references, this + /// allocates new memory. + /// If @a _toMemory is true, directly stores the data in the memory pos on the stack and + /// updates it. + void appendStackVariableInitialisation(Type const& _type, bool _toMemory = false); + /// Appends code for a State Variable accessor function void appendStateVariableAccessor(VariableDeclaration const& _varDecl); diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index b90b88846..01876b5a7 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -721,9 +721,13 @@ bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const } else { - // Require that the base type is the same, not only convertible. - // This disallows assignment of nested arrays from storage to memory for now. - if (*getBaseType() != *convertTo.getBaseType()) + // Conversion to storage pointer or to memory, we de not copy element-for-element here, so + // require that the base type is the same, not only convertible. + // This disallows assignment of nested dynamic arrays from storage to memory for now. + if ( + *copyForLocationIfReference(location(), getBaseType()) != + *copyForLocationIfReference(location(), convertTo.getBaseType()) + ) return false; if (isDynamicallySized() != convertTo.isDynamicallySized()) return false; @@ -822,16 +826,16 @@ string ArrayType::toString(bool _short) const TypePointer ArrayType::externalType() const { if (m_arrayKind != ArrayKind::Ordinary) - return shared_from_this(); + return this->copyForLocation(DataLocation::Memory, true); if (!m_baseType->externalType()) return TypePointer(); if (m_baseType->getCategory() == Category::Array && m_baseType->isDynamicallySized()) return TypePointer(); if (isDynamicallySized()) - return std::make_shared(DataLocation::CallData, m_baseType->externalType()); + return std::make_shared(DataLocation::Memory, m_baseType->externalType()); else - return std::make_shared(DataLocation::CallData, m_baseType->externalType(), m_length); + return std::make_shared(DataLocation::Memory, m_baseType->externalType(), m_length); } TypePointer ArrayType::copyForLocation(DataLocation _location, bool _isPointer) const @@ -903,7 +907,7 @@ MemberList const& ContractType::getMembers() const for (auto const& it: m_contract.getInterfaceFunctions()) members.push_back(MemberList::Member( it.second->getDeclaration().getName(), - it.second, + it.second->asMemberFunction(), &it.second->getDeclaration() )); m_members.reset(new MemberList(members)); @@ -970,6 +974,22 @@ bool StructType::operator==(Type const& _other) const return ReferenceType::operator==(other) && other.m_struct == m_struct; } +unsigned StructType::getCalldataEncodedSize(bool _padded) const +{ + unsigned size = 0; + for (auto const& member: getMembers()) + if (!member.type->canLiveOutsideStorage()) + return 0; + else + { + unsigned memberSize = member.type->getCalldataEncodedSize(_padded); + if (memberSize == 0) + return 0; + size += memberSize; + } + return size; +} + u256 StructType::getStorageSize() const { return max(1, getMembers().getStorageSize()); @@ -1284,6 +1304,7 @@ MemberList const& FunctionType::getMembers() const strings(), Location::SetValue, false, + nullptr, m_gasSet, m_valueSet ) @@ -1300,6 +1321,7 @@ MemberList const& FunctionType::getMembers() const strings(), Location::SetGas, false, + nullptr, m_gasSet, m_valueSet ) @@ -1404,11 +1426,45 @@ TypePointer FunctionType::copyAndSetGasOrValue(bool _setGas, bool _setValue) con m_returnParameterNames, m_location, m_arbitraryParameters, + m_declaration, m_gasSet || _setGas, m_valueSet || _setValue ); } +FunctionTypePointer FunctionType::asMemberFunction() const +{ + TypePointers parameterTypes; + for (auto const& t: m_parameterTypes) + { + auto refType = dynamic_cast(t.get()); + if (refType && refType->location() == DataLocation::CallData) + parameterTypes.push_back(refType->copyForLocation(DataLocation::Memory, false)); + else + parameterTypes.push_back(t); + } + + //@todo make this more intelligent once we support destructuring assignments + TypePointers returnParameterTypes; + vector returnParameterNames; + if (!m_returnParameterTypes.empty() && m_returnParameterTypes.front()->getCalldataEncodedSize() > 0) + { + returnParameterTypes.push_back(m_returnParameterTypes.front()); + returnParameterNames.push_back(m_returnParameterNames.front()); + } + return make_shared( + parameterTypes, + returnParameterTypes, + m_parameterNames, + returnParameterNames, + m_location, + m_arbitraryParameters, + m_declaration, + m_gasSet, + m_valueSet + ); +} + vector const FunctionType::getParameterTypeNames() const { vector names; diff --git a/libsolidity/Types.h b/libsolidity/Types.h index cca5dde71..9d412cd68 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -542,6 +542,7 @@ public: virtual bool isImplicitlyConvertibleTo(const Type& _convertTo) const override; virtual TypePointer unaryOperatorResult(Token::Value _operator) const override; virtual bool operator==(Type const& _other) const override; + virtual unsigned getCalldataEncodedSize(bool _padded) const override; virtual u256 getStorageSize() const override; virtual bool canLiveOutsideStorage() const override; virtual unsigned getSizeOnStack() const override { return 2; } @@ -669,17 +670,19 @@ public: strings _returnParameterNames = strings(), Location _location = Location::Internal, bool _arbitraryParameters = false, + Declaration const* _declaration = nullptr, bool _gasSet = false, bool _valueSet = false ): - m_parameterTypes (_parameterTypes), - m_returnParameterTypes (_returnParameterTypes), - m_parameterNames (_parameterNames), - m_returnParameterNames (_returnParameterNames), - m_location (_location), - m_arbitraryParameters (_arbitraryParameters), - m_gasSet (_gasSet), - m_valueSet (_valueSet) + m_parameterTypes(_parameterTypes), + m_returnParameterTypes(_returnParameterTypes), + m_parameterNames(_parameterNames), + m_returnParameterNames(_returnParameterNames), + m_location(_location), + m_arbitraryParameters(_arbitraryParameters), + m_gasSet(_gasSet), + m_valueSet(_valueSet), + m_declaration(_declaration) {} TypePointers const& getParameterTypes() const { return m_parameterTypes; } @@ -733,6 +736,12 @@ public: /// of the parameters to fals. TypePointer copyAndSetGasOrValue(bool _setGas, bool _setValue) const; + /// @returns a copy of this function type where all return parameters of dynamic size are + /// removed and the location of reference types is changed from CallData to Memory. + /// This is needed if external functions are called on other contracts, as they cannot return + /// dynamic values. + FunctionTypePointer asMemberFunction() const; + private: static TypePointers parseElementaryTypeVector(strings const& _types); diff --git a/libweb3jsonrpc/CMakeLists.txt b/libweb3jsonrpc/CMakeLists.txt index e265910fa..c65efd39b 100644 --- a/libweb3jsonrpc/CMakeLists.txt +++ b/libweb3jsonrpc/CMakeLists.txt @@ -13,7 +13,7 @@ include_directories(BEFORE ${JSONCPP_INCLUDE_DIRS}) include_directories(BEFORE ..) include_directories(${MHD_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) -include_directories(${LEVELDB_INCLUDE_DIRS}) +include_directories(${DB_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS}) set(EXECUTABLE web3jsonrpc) @@ -22,7 +22,6 @@ file(GLOB HEADERS "*.h") add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) -target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${JSONCPP_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${JSON_RPC_CPP_SERVER_LIBRARIES}) target_link_libraries(${EXECUTABLE} ${MHD_LIBRARIES}) @@ -55,4 +54,3 @@ install( TARGETS ${EXECUTABLE} RUNTIME DESTINATION bin ARCHIVE DESTINATION lib L install( FILES ${HEADERS} DESTINATION include/${EXECUTABLE} ) add_custom_target(aux_json SOURCES "spec.json") - diff --git a/libweb3jsonrpc/WebThreeStubServer.h b/libweb3jsonrpc/WebThreeStubServer.h index 290bf456c..4d545c90e 100644 --- a/libweb3jsonrpc/WebThreeStubServer.h +++ b/libweb3jsonrpc/WebThreeStubServer.h @@ -23,11 +23,7 @@ #pragma once -#pragma warning(push) -#pragma warning(disable: 4100 4267) -#include -#pragma warning(pop) - +#include #include "WebThreeStubServerBase.h" namespace dev @@ -99,9 +95,9 @@ private: dev::WebThreeDirect& m_web3; dev::eth::KeyManager& m_keyMan; dev::eth::TrivialGasPricer& m_gp; - leveldb::ReadOptions m_readOptions; - leveldb::WriteOptions m_writeOptions; - leveldb::DB* m_db; + ldb::ReadOptions m_readOptions; + ldb::WriteOptions m_writeOptions; + ldb::DB* m_db; std::function m_setMiningBenefactor; std::unordered_map m_sessions; diff --git a/libwebthree/CMakeLists.txt b/libwebthree/CMakeLists.txt index b72945cab..015c28f46 100644 --- a/libwebthree/CMakeLists.txt +++ b/libwebthree/CMakeLists.txt @@ -12,7 +12,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) include_directories(BEFORE ..) -include_directories(${LEVELDB_INCLUDE_DIRS}) +include_directories(${DB_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS}) set(EXECUTABLE webthree) @@ -21,8 +21,6 @@ file(GLOB HEADERS "*.h") add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) -target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES}) - target_link_libraries(${EXECUTABLE} ethereum) target_link_libraries(${EXECUTABLE} evm) target_link_libraries(${EXECUTABLE} lll) diff --git a/libwebthree/WebThree.cpp b/libwebthree/WebThree.cpp index d7fb5de7c..513581841 100644 --- a/libwebthree/WebThree.cpp +++ b/libwebthree/WebThree.cpp @@ -80,7 +80,7 @@ std::string WebThreeDirect::composeClientVersion(std::string const& _client, std #else char const* jit = ""; #endif - return _client + "v" + dev::Version + "-" + string(DEV_QUOTED(ETH_COMMIT_HASH)).substr(0, 8) + (ETH_CLEAN_REPO ? "" : "*") + "/" + _clientName + "/" DEV_QUOTED(ETH_BUILD_TYPE) "-" DEV_QUOTED(ETH_BUILD_PLATFORM) + jit; + return _client + "-" + "v" + dev::Version + "-" + string(DEV_QUOTED(ETH_COMMIT_HASH)).substr(0, 8) + (ETH_CLEAN_REPO ? "" : "*") + "/" + _clientName + "/" DEV_QUOTED(ETH_BUILD_TYPE) "-" DEV_QUOTED(ETH_BUILD_PLATFORM) + jit; } p2p::NetworkPreferences const& WebThreeDirect::networkPreferences() const diff --git a/libwhisper/BloomFilter.cpp b/libwhisper/BloomFilter.cpp index cff69c664..554274011 100644 --- a/libwhisper/BloomFilter.cpp +++ b/libwhisper/BloomFilter.cpp @@ -25,40 +25,4 @@ using namespace std; using namespace dev; using namespace dev::shh; -static unsigned const c_mask[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; - -void TopicBloomFilter::addRaw(AbridgedTopic const& _h) -{ - *this |= _h; - for (unsigned i = 0; i < CounterSize; ++i) - if (isBitSet(_h, i)) - { - if (m_refCounter[i] != numeric_limits::max()) - m_refCounter[i]++; - else - BOOST_THROW_EXCEPTION(Overflow()); - } -} - -void TopicBloomFilter::removeRaw(AbridgedTopic const& _h) -{ - for (unsigned i = 0; i < CounterSize; ++i) - if (isBitSet(_h, i)) - { - if (m_refCounter[i]) - m_refCounter[i]--; - - if (!m_refCounter[i]) - (*this)[i / 8] &= ~c_mask[i % 8]; - } -} - -bool TopicBloomFilter::isBitSet(AbridgedTopic const& _h, unsigned _index) -{ - unsigned iByte = _index / 8; - unsigned iBit = _index % 8; - return (_h[iByte] & c_mask[iBit]) != 0; -} - - diff --git a/libwhisper/BloomFilter.h b/libwhisper/BloomFilter.h index 0ca460805..157f4b011 100644 --- a/libwhisper/BloomFilter.h +++ b/libwhisper/BloomFilter.h @@ -28,30 +28,71 @@ namespace dev namespace shh { -class TopicBloomFilter: public AbridgedTopic +template +class TopicBloomFilterBase: public FixedHash { public: - TopicBloomFilter() { init(); } - TopicBloomFilter(AbridgedTopic const& _h): AbridgedTopic(_h) { init(); } + TopicBloomFilterBase() { init(); } + TopicBloomFilterBase(FixedHash const& _h): FixedHash(_h) { init(); } - void addBloom(AbridgedTopic const& _h) { addRaw(_h.template bloomPart()); } - void removeBloom(AbridgedTopic const& _h) { removeRaw(_h.template bloomPart()); } - bool containsBloom(AbridgedTopic const& _h) const { return contains(_h.template bloomPart()); } + void addBloom(dev::shh::AbridgedTopic const& _h) { addRaw(_h.template bloomPart()); } + void removeBloom(dev::shh::AbridgedTopic const& _h) { removeRaw(_h.template bloomPart()); } + bool containsBloom(dev::shh::AbridgedTopic const& _h) const { return this->contains(_h.template bloomPart()); } - void addRaw(AbridgedTopic const& _h); - void removeRaw(AbridgedTopic const& _h); - bool containsRaw(AbridgedTopic const& _h) const { return contains(_h); } + void addRaw(FixedHash const& _h); + void removeRaw(FixedHash const& _h); + bool containsRaw(FixedHash const& _h) const { return this->contains(_h); } enum { BitsPerBloom = 3 }; private: void init() { for (unsigned i = 0; i < CounterSize; ++i) m_refCounter[i] = 0; } - static bool isBitSet(AbridgedTopic const& _h, unsigned _index); + static bool isBitSet(FixedHash const& _h, unsigned _index); - enum { CounterSize = 8 * TopicBloomFilter::size }; + enum { CounterSize = 8 * TopicBloomFilterBase::size }; std::array m_refCounter; }; +static unsigned const c_powerOfTwoBitMmask[8] = { 1, 2, 4, 8, 16, 32, 64, 128 }; + +template +void TopicBloomFilterBase::addRaw(FixedHash const& _h) +{ + *this |= _h; + for (unsigned i = 0; i < CounterSize; ++i) + if (isBitSet(_h, i)) + { + if (m_refCounter[i] != std::numeric_limits::max()) + m_refCounter[i]++; + else + BOOST_THROW_EXCEPTION(Overflow()); + } +} + +template +void TopicBloomFilterBase::removeRaw(FixedHash const& _h) +{ + for (unsigned i = 0; i < CounterSize; ++i) + if (isBitSet(_h, i)) + { + if (m_refCounter[i]) + m_refCounter[i]--; + + if (!m_refCounter[i]) + (*this)[i / 8] &= ~c_powerOfTwoBitMmask[i % 8]; + } +} + +template +bool TopicBloomFilterBase::isBitSet(FixedHash const& _h, unsigned _index) +{ + unsigned iByte = _index / 8; + unsigned iBit = _index % 8; + return (_h[iByte] & c_powerOfTwoBitMmask[iBit]) != 0; +} + +using TopicBloomFilter = TopicBloomFilterBase; + } } diff --git a/libwhisper/CMakeLists.txt b/libwhisper/CMakeLists.txt index 6ee935a90..8a1439c8b 100644 --- a/libwhisper/CMakeLists.txt +++ b/libwhisper/CMakeLists.txt @@ -12,7 +12,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSTATICLIB") aux_source_directory(. SRC_LIST) include_directories(BEFORE ..) -include_directories(${LEVELDB_INCLUDE_DIRS}) +include_directories(${DB_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS}) set(EXECUTABLE whisper) @@ -21,8 +21,6 @@ file(GLOB HEADERS "*.h") add_library(${EXECUTABLE} ${SRC_LIST} ${HEADERS}) -target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES}) - target_link_libraries(${EXECUTABLE} ethcore) target_link_libraries(${EXECUTABLE} devcrypto) target_link_libraries(${EXECUTABLE} devcore) diff --git a/libwhisper/Common.cpp b/libwhisper/Common.cpp index 7f5b8ed06..32acbdd8e 100644 --- a/libwhisper/Common.cpp +++ b/libwhisper/Common.cpp @@ -95,9 +95,9 @@ TopicFilter::TopicFilter(RLP const& _r) } } -AbridgedTopic TopicFilter::exportBloom() const +FixedHash TopicFilter::exportBloom() const { - AbridgedTopic ret; + FixedHash ret; for (TopicMask const& t: m_topicMasks) for (auto const& i: t) ret |= i.first.template bloomPart(); diff --git a/libwhisper/Common.h b/libwhisper/Common.h index 07c5b3317..71435603e 100644 --- a/libwhisper/Common.h +++ b/libwhisper/Common.h @@ -59,6 +59,8 @@ enum WhisperPacket PacketCount }; +enum { TopicBloomFilterSize = 8 }; + using AbridgedTopic = FixedHash<4>; using Topic = h256; @@ -105,7 +107,7 @@ public: void streamRLP(RLPStream& _s) const { _s << m_topicMasks; } h256 sha3() const; bool matches(Envelope const& _m) const; - AbridgedTopic exportBloom() const; + FixedHash exportBloom() const; private: TopicMasks m_topicMasks; diff --git a/libwhisper/WhisperPeer.cpp b/libwhisper/WhisperPeer.cpp index 0b75def28..0be59592d 100644 --- a/libwhisper/WhisperPeer.cpp +++ b/libwhisper/WhisperPeer.cpp @@ -29,7 +29,7 @@ using namespace dev; using namespace dev::p2p; using namespace dev::shh; -WhisperPeer::WhisperPeer(Session* _s, HostCapabilityFace* _h, unsigned _i, CapDesc const&): Capability(_s, _h, _i) +WhisperPeer::WhisperPeer(std::shared_ptr _s, HostCapabilityFace* _h, unsigned _i, CapDesc const&): Capability(_s, _h, _i) { RLPStream s; sealAndSend(prep(s, StatusPacket, 1) << version()); diff --git a/libwhisper/WhisperPeer.h b/libwhisper/WhisperPeer.h index 9344da024..5cb124568 100644 --- a/libwhisper/WhisperPeer.h +++ b/libwhisper/WhisperPeer.h @@ -51,7 +51,7 @@ class WhisperPeer: public Capability friend class WhisperHost; public: - WhisperPeer(Session* _s, HostCapabilityFace* _h, unsigned _i, CapDesc const& _cap); + WhisperPeer(std::shared_ptr _s, HostCapabilityFace* _h, unsigned _i, CapDesc const& _cap); virtual ~WhisperPeer(); static std::string name() { return "shh"; } diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 8cb901a39..655be1c08 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -374,29 +374,60 @@ void CodeModel::gasEstimation(solidity::CompilerStack const& _cs) dev::solidity::SourceUnit const& sourceUnit = _cs.getAST(*contractDefinition.getLocation().sourceName); AssemblyItems const* items = _cs.getRuntimeAssemblyItems(n); std::map gasCosts = GasEstimator::breakToStatementLevel(GasEstimator::structuralEstimation(*items, std::vector({&sourceUnit})), {&sourceUnit}); + + auto gasToString = [](GasMeter::GasConsumption const& _gas) + { + if (_gas.isInfinite) + return QString("0"); + else + return QString::fromStdString(toString(_gas.value)); + }; + + // Structural gas costs (per opcode) for (auto gasItem = gasCosts.begin(); gasItem != gasCosts.end(); ++gasItem) { SourceLocation const& location = gasItem->first->getLocation(); GasMeter::GasConsumption cost = gasItem->second; - std::stringstream v; - v << cost.value; - m_gasCostsMaps->push(sourceName, location.start, location.end, QString::fromStdString(v.str()), cost.isInfinite, GasMap::type::Statement); + m_gasCostsMaps->push(sourceName, location.start, location.end, gasToString(cost), cost.isInfinite, GasMap::type::Statement); } - if (contractDefinition.getConstructor() != nullptr) + eth::AssemblyItems const& runtimeAssembly = *_cs.getRuntimeAssemblyItems(n); + QString contractName = QString::fromStdString(contractDefinition.getName()); + // Functional gas costs (per function, but also for accessors) + for (auto it: contractDefinition.getInterfaceFunctions()) { - GasMeter::GasConsumption cost = GasEstimator::functionalEstimation(*_cs.getRuntimeAssemblyItems(n), contractDefinition.getConstructor()->externalSignature()); - std::stringstream v; - v << cost.value; - m_gasCostsMaps->push(sourceName, contractDefinition.getConstructor()->getLocation().start, contractDefinition.getConstructor()->getLocation().end, QString::fromStdString(v.str()), cost.isInfinite, GasMap::type::Constructor); + if (!it.second->hasDeclaration()) + continue; + SourceLocation loc = it.second->getDeclaration().getLocation(); + GasMeter::GasConsumption cost = GasEstimator::functionalEstimation(runtimeAssembly, it.second->externalSignature()); + m_gasCostsMaps->push(sourceName, loc.start, loc.end, gasToString(cost), cost.isInfinite, GasMap::type::Function, + contractName, QString::fromStdString(it.second->getDeclaration().getName())); } - - for (auto func: contractDefinition.getDefinedFunctions()) + if (auto const* fallback = contractDefinition.getFallbackFunction()) + { + SourceLocation loc = fallback->getLocation(); + GasMeter::GasConsumption cost = GasEstimator::functionalEstimation(runtimeAssembly, "INVALID"); + m_gasCostsMaps->push(sourceName, loc.start, loc.end, gasToString(cost), cost.isInfinite, GasMap::type::Function, + contractName, "fallback"); + } + for (auto const& it: contractDefinition.getDefinedFunctions()) { - GasMeter::GasConsumption cost = GasEstimator::functionalEstimation(*_cs.getRuntimeAssemblyItems(n), func->externalSignature()); - std::stringstream v; - v << cost.value; - m_gasCostsMaps->push(sourceName, func->getLocation().start, func->getLocation().end, QString::fromStdString(v.str()), cost.isInfinite, GasMap::type::Function); + if (it->isPartOfExternalInterface() || it->isConstructor()) + continue; + SourceLocation loc = it->getLocation(); + size_t entry = _cs.getFunctionEntryPoint(n, *it); + GasEstimator::GasConsumption cost = GasEstimator::GasConsumption::infinite(); + if (entry > 0) + cost = GasEstimator::functionalEstimation(runtimeAssembly, entry, *it); + m_gasCostsMaps->push(sourceName, loc.start, loc.end, gasToString(cost), cost.isInfinite, GasMap::type::Function, + contractName, QString::fromStdString(it->getName())); + } + if (auto const* constructor = contractDefinition.getConstructor()) + { + SourceLocation loc = constructor->getLocation(); + GasMeter::GasConsumption cost = GasEstimator::functionalEstimation(*_cs.getAssemblyItems(n)); + m_gasCostsMaps->push(sourceName, loc.start, loc.end, gasToString(cost), cost.isInfinite, GasMap::type::Constructor, + contractName, contractName); } } } @@ -409,6 +440,14 @@ QVariantList CodeModel::gasCostByDocumentId(QString const& _documentId) const return QVariantList(); } +QVariantList CodeModel::gasCostBy(QString const& _contractName, QString const& _functionName) const +{ + if (m_gasCostsMaps) + return m_gasCostsMaps->gasCostsBy(_contractName, _functionName); + else + return QVariantList(); +} + void CodeModel::collectContracts(dev::solidity::CompilerStack const& _cs, std::vector const& _sourceNames) { Guard pl(x_pendingContracts); @@ -617,9 +656,9 @@ void CodeModel::setOptimizeCode(bool _value) emit scheduleCompilationJob(++m_backgroundJobId); } -void GasMapWrapper::push(QString _source, int _start, int _end, QString _value, bool _isInfinite, GasMap::type _type) +void GasMapWrapper::push(QString _source, int _start, int _end, QString _value, bool _isInfinite, GasMap::type _type, QString _contractName, QString _functionName) { - GasMap* gas = new GasMap(_start, _end, _value, _isInfinite, _type, this); + GasMap* gas = new GasMap(_start, _end, _value, _isInfinite, _type, _contractName, _functionName, this); m_gasMaps.find(_source).value().push_back(QVariant::fromValue(gas)); } @@ -642,3 +681,17 @@ QVariantList GasMapWrapper::gasCostsByDocId(QString _source) return QVariantList(); } +QVariantList GasMapWrapper::gasCostsBy(QString _contractName, QString _functionName) +{ + QVariantList gasMap; + for (auto const& map: m_gasMaps) + { + for (auto const& gas: map) + { + if (gas.value()->contractName() == _contractName && (_functionName.isEmpty() || gas.value()->functionName() == _functionName)) + gasMap.push_back(gas); + } + } + return gasMap; +} + diff --git a/mix/CodeModel.h b/mix/CodeModel.h index 7841c7142..e51eabf51 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "SolidityType.h" #include "QBigInt.h" @@ -140,6 +141,8 @@ class GasMap: public QObject Q_PROPERTY(QString gas MEMBER m_gas CONSTANT) Q_PROPERTY(bool isInfinite MEMBER m_isInfinite CONSTANT) Q_PROPERTY(QString codeBlockType READ codeBlockType CONSTANT) + Q_PROPERTY(QString contractName MEMBER m_contractName CONSTANT) + Q_PROPERTY(QString functionName MEMBER m_functionName CONSTANT) public: @@ -150,13 +153,19 @@ public: Constructor }; - GasMap(int _start, int _end, QString _gas, bool _isInfinite, type _type, QObject* _parent): QObject(_parent), m_start(_start), m_end(_end), m_gas(_gas), m_isInfinite(_isInfinite), m_type(_type) {} + GasMap(int _start, int _end, QString _gas, bool _isInfinite, type _type, QString _contractName, QString _functionName, QObject* _parent): QObject(_parent), + m_start(_start), m_end(_end), m_gas(_gas), m_isInfinite(_isInfinite), m_type(_type), m_contractName(_contractName), m_functionName(_functionName) {} + QString contractName() { return m_contractName; } + QString functionName() { return m_functionName; } +private: int m_start; int m_end; QString m_gas; bool m_isInfinite; type m_type; + QString m_contractName; + QString m_functionName; QString codeBlockType() const { @@ -178,10 +187,11 @@ class GasMapWrapper: public QObject public: GasMapWrapper(QObject* _parent = nullptr): QObject(_parent){} - void push(QString _source, int _start, int _end, QString _value, bool _isInfinite, GasMap::type _type); + void push(QString _source, int _start, int _end, QString _value, bool _isInfinite, GasMap::type _type, QString _contractName = "", QString _functionName = ""); bool contains(QString _key); void insert(QString _source, QVariantList _variantList); QVariantList gasCostsByDocId(QString _source); + QVariantList gasCostsBy(QString _contractName, QString _functionName = ""); private: GasCostsMaps m_gasMaps; @@ -200,6 +210,8 @@ public: Q_PROPERTY(bool compiling READ isCompiling NOTIFY stateChanged) Q_PROPERTY(bool hasContract READ hasContract NOTIFY codeChanged) Q_PROPERTY(bool optimizeCode MEMBER m_optimizeCode WRITE setOptimizeCode) + Q_PROPERTY(int callStipend READ callStipend) + Q_PROPERTY(int txGas READ txGas) /// @returns latest compilation results for contracts QVariantMap contracts() const; @@ -234,7 +246,10 @@ public: void gasEstimation(solidity::CompilerStack const& _cs); /// Gas cost by doc id Q_INVOKABLE QVariantList gasCostByDocumentId(QString const& _documentId) const; + Q_INVOKABLE QVariantList gasCostBy(QString const& _contractName, QString const& _functionName) const; Q_INVOKABLE void setOptimizeCode(bool _value); + int txGas() { return static_cast(dev::eth::c_txGas); } + int callStipend() { return static_cast(dev::eth::c_callStipend); } signals: /// Emited on compilation state change diff --git a/mix/MixClient.cpp b/mix/MixClient.cpp index befd1d056..0b1c7c44f 100644 --- a/mix/MixClient.cpp +++ b/mix/MixClient.cpp @@ -229,6 +229,7 @@ void MixClient::executeTransaction(Transaction const& _t, State& _state, bool _c case TransactionException::BadInstruction: case TransactionException::InvalidSignature: case TransactionException::InvalidNonce: + case TransactionException::InvalidFormat: case TransactionException::BadRLP: BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("Internal execution error")); } diff --git a/mix/qml/Block.qml b/mix/qml/Block.qml index 6fb274ccd..75d34a766 100644 --- a/mix/qml/Block.qml +++ b/mix/qml/Block.qml @@ -16,23 +16,24 @@ ColumnLayout property int number property int blockWidth: Layout.preferredWidth - statusWidth - horizontalMargin property int horizontalMargin: 10 - property int trHeight: 30 + property int trHeight: 35 spacing: 0 property int openedTr: 0 property int blockIndex property variant scenario + property string labelColor: "#414141" function calculateHeight() { if (transactions) { if (index >= 0) - return 30 + 30 * transactions.count + openedTr + return trHeight + trHeight * transactions.count + openedTr else - return 30 + return trHeight } else - return 30 + return trHeight } onOpenedTrChanged: @@ -41,31 +42,67 @@ ColumnLayout height = calculateHeight() } + DebuggerPaneStyle { + id: dbgStyle + } + Rectangle + { + id: top + Layout.preferredWidth: blockWidth + height: 10 + anchors.bottom: rowHeader.top + color: "#DEDCDC" + radius: 15 + anchors.left: parent.left + anchors.leftMargin: statusWidth + anchors.bottomMargin: -5 + } RowLayout { Layout.preferredHeight: trHeight Layout.preferredWidth: blockWidth id: rowHeader + spacing: 0 Rectangle { - color: "#DEDCDC" Layout.preferredWidth: blockWidth Layout.preferredHeight: trHeight - radius: 4 + color: "#DEDCDC" anchors.left: parent.left - anchors.leftMargin: statusWidth + 5 + anchors.leftMargin: statusWidth Label { anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left anchors.leftMargin: horizontalMargin + font.pointSize: dbgStyle.absoluteSize(1) + color: "#adadad" text: { - if (status === "mined") + if (number === -2) + return qsTr("STARTING PARAMETERS") + else if (status === "mined") return qsTr("BLOCK") + " " + number else - return qsTr("BLOCK") + " pending" + return qsTr("PENDING TRANSACTIONS") + } + } + + Label + { + text: qsTr("EDIT") + color: "#1397da" + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: 14 + MouseArea + { + anchors.fill: parent + onClicked: + { + // load edit block panel + } } } } @@ -75,11 +112,11 @@ ColumnLayout { id: transactionRepeater model: transactions - RowLayout { id: rowTransaction Layout.preferredHeight: trHeight + spacing: 0 function displayContent() { logsText.text = "" @@ -99,7 +136,7 @@ ColumnLayout var p = log.param.get(i) logsText.text += p.name + " = " + p.value + " - indexed:" + p.indexed + "\n" } - else{ + else { logsText.text += "From : " + log.address + "\n" } } @@ -112,18 +149,19 @@ ColumnLayout { id: trSaveStatus Layout.preferredWidth: statusWidth - Layout.preferredHeight: trHeight + Layout.preferredHeight: parent.height color: "transparent" anchors.top: parent.top property bool saveStatus - Image { + anchors.top: parent.top + anchors.left: parent.left + anchors.leftMargin: -9 + anchors.topMargin: -9 id: saveStatusImage source: "qrc:/qml/img/recyclediscard@2x.png" - width: statusWidth + width: statusWidth + 20 fillMode: Image.PreserveAspectFit - anchors.verticalCenter: parent.verticalCenter - anchors.horizontalCenter: parent.horizontalCenter } Component.onCompleted: @@ -160,43 +198,71 @@ ColumnLayout color: "#DEDCDC" id: rowContentTr anchors.top: parent.top + + MouseArea + { + anchors.fill: parent + onDoubleClicked: + { + transactionDialog.stateAccounts = scenario.accounts + transactionDialog.execute = false + transactionDialog.open(index, blockIndex, transactions.get(index)) + } + } + ColumnLayout { anchors.top: parent.top - spacing: 10 + width: parent.width + spacing: 20 RowLayout { anchors.top: parent.top - anchors.verticalCenter: parent.verticalCenter - spacing: cellSpacing - Text + Layout.fillWidth: true + Rectangle { - id: hash + Layout.preferredWidth: fromWidth anchors.left: parent.left anchors.leftMargin: horizontalMargin - Layout.preferredWidth: fromWidth - elide: Text.ElideRight - maximumLineCount: 1 - text: { - if (index >= 0) - return transactions.get(index).sender - else - return "" + Text + { + id: hash + width: parent.width - 30 + elide: Text.ElideRight + anchors.verticalCenter: parent.verticalCenter + maximumLineCount: 1 + color: labelColor + font.pointSize: dbgStyle.absoluteSize(1) + font.bold: true + text: { + if (index >= 0) + return transactions.get(index).sender + else + return "" + } } } - Text + Rectangle { - id: func - text: { - if (index >= 0) - parent.userFrienldyToken(transactions.get(index).label) - else - return "" - } - elide: Text.ElideRight - maximumLineCount: 1 Layout.preferredWidth: toWidth + Text + { + id: func + text: { + if (index >= 0) + parent.parent.userFrienldyToken(transactions.get(index).label) + else + return "" + } + elide: Text.ElideRight + anchors.verticalCenter: parent.verticalCenter + color: labelColor + font.pointSize: dbgStyle.absoluteSize(1) + font.bold: true + maximumLineCount: 1 + width: parent.width + } } function userFrienldyToken(value) @@ -212,17 +278,25 @@ ColumnLayout return value } - Text + Rectangle { - id: returnValue - elide: Text.ElideRight - maximumLineCount: 1 Layout.preferredWidth: valueWidth - text: { - if (index >= 0 && transactions.get(index).returned) - return transactions.get(index).returned - else - return "" + Text + { + id: returnValue + elide: Text.ElideRight + anchors.verticalCenter: parent.verticalCenter + maximumLineCount: 1 + color: labelColor + font.bold: true + font.pointSize: dbgStyle.absoluteSize(1) + width: parent.width - 30 + text: { + if (index >= 0 && transactions.get(index).returned) + return transactions.get(index).returned + else + return "" + } } } @@ -236,7 +310,11 @@ ColumnLayout { id: logs anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter anchors.leftMargin: 10 + color: labelColor + font.bold: true + font.pointSize: dbgStyle.absoluteSize(1) text: { if (index >= 0 && transactions.get(index).logs && transactions.get(index).logs.count) return transactions.get(index).logs.count @@ -251,60 +329,6 @@ ColumnLayout } } } - - 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 @@ -340,6 +364,39 @@ ColumnLayout } } } + + Rectangle + { + width: debugActionWidth + height: trHeight + anchors.left: rowContentTr.right + anchors.topMargin: -6 + anchors.top: rowContentTr.top + anchors.leftMargin: -50 + color: "transparent" + + Image { + id: debugImg + source: "qrc:/qml/img/rightarrow@2x.png" + width: debugActionWidth + 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); + } + } + } + } } } } diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml index d3fad6fda..02ff72be2 100644 --- a/mix/qml/BlockChain.qml +++ b/mix/qml/BlockChain.qml @@ -18,15 +18,27 @@ ColumnLayout { property int previousWidth property variant debugTrRequested: [] signal chainChanged + signal chainReloaded + + Connections + { + target: codeModel + onContractRenamed: { + rebuild.startBlinking() + } + onNewContractCompiled: { + rebuild.startBlinking() + } + } onChainChanged: { - reBuildNeeded.start() + rebuild.startBlinking() } onWidthChanged: { - - if (width <= 630 || previousWidth <= 630) + var minWidth = scenarioMinWidth - 20 // margin + if (width <= minWidth || previousWidth <= minWidth) { fromWidth = 100 toWidth = 100 @@ -47,7 +59,7 @@ ColumnLayout { if (!scenario) return; if (model) - chainChanged() + rebuild.startBlinking() model = scenario blockModel.clear() for (var b in model.blocks) @@ -56,11 +68,11 @@ ColumnLayout { } property int statusWidth: 30 - property int fromWidth: 100 + property int fromWidth: 150 property int toWidth: 100 property int valueWidth: 200 - property int logsWidth: 50 - property int debugActionWidth: 50 + property int logsWidth: 40 + property int debugActionWidth: 40 property int horizontalMargin: 10 property int cellSpacing: 10 @@ -68,23 +80,30 @@ ColumnLayout { { id: header spacing: 0 - Layout.preferredHeight: 25 - Image { - id: debugImage - source: "qrc:/qml/img/recycleicon@2x.png" + Layout.preferredHeight: 30 + Rectangle + { Layout.preferredWidth: statusWidth - Layout.preferredHeight: 25 - fillMode: Image.PreserveAspectFit + Layout.preferredHeight: parent.height + color: "transparent" + Image { + id: debugImage + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + source: "qrc:/qml/img/recycleicon@2x.png" + width: statusWidth + 20 + fillMode: Image.PreserveAspectFit + } } Rectangle { - Layout.preferredWidth: fromWidth + cellSpacing + Layout.preferredWidth: fromWidth Label { anchors.verticalCenter: parent.verticalCenter text: "From" anchors.left: parent.left - anchors.leftMargin: horizontalMargin + 5 + anchors.leftMargin: horizontalMargin } } Label @@ -120,12 +139,25 @@ ColumnLayout { { id: blockChainScrollView anchors.fill: parent - anchors.topMargin: 10 + anchors.topMargin: 8 ColumnLayout { id: blockChainLayout width: parent.width - spacing: 10 + spacing: 20 + + Block + { + scenario: blockChainPanel.model + Layout.preferredWidth: blockChainScrollView.width + Layout.preferredHeight: 60 + blockIndex: -1 + transactions: [] + status: "" + number: -2 + trHeight: 60 + } + Repeater // List of blocks { id: blockChainRepeater @@ -218,158 +250,171 @@ ColumnLayout { Layout.preferredWidth: parent.width RowLayout { - width: 4 * 100 + anchors.horizontalCenter: parent.horizontalCenter 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++) + spacing: 20 + + Rectangle { + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + + ScenarioButton { + id: rebuild + text: qsTr("Rebuild") + width: 100 + height: 30 + roundLeft: true + roundRight: true + onClicked: { - 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 (ensureNotFuturetime.running) + return; + stopBlinking() + var retBlocks = []; + var bAdded = 0; + for (var j = 0; j < model.blocks.length; j++) { - if (blockModel.get(j).transactions.get(k).saveStatus) + 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++) { - var tr = model.blocks[j].transactions[k] - tr.saveStatus = true - block.transactions.push(tr); + 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 (block.transactions.length > 0) + if (retBlocks.length === 0) + retBlocks.push(projectModel.stateListModel.createEmptyBlock()) + else { - bAdded++ - block.number = bAdded - block.status = "mined" - retBlocks.push(block) + 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); } - if (retBlocks.length === 0) - retBlocks.push(projectModel.stateListModel.createEmptyBlock()) - else - { - var last = retBlocks[retBlocks.length - 1] - last.number = -1 - last.status = "pending" - } + buttonShortcut: "" + sourceImg: "qrc:/qml/img/recycleicon@2x.png" + } + } - model.blocks = retBlocks - blockModel.clear() - for (var j = 0; j < model.blocks.length; j++) - blockModel.append(model.blocks[j]) - ensureNotFuturetime.start() - clientModel.setupScenario(model); + Rectangle + { + Layout.preferredWidth: 200 + Layout.preferredHeight: 30 + color: "transparent" + + ScenarioButton { + id: addTransaction + text: qsTr("Add Tx") + 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) + } + width: 100 + height: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/sendtransactionicon@2x.png" + roundLeft: true + roundRight: false } - Layout.preferredWidth: 100 - Layout.preferredHeight: 30 - buttonShortcut: "" - sourceImg: "qrc:/qml/img/recycleicon@2x.png" Timer { - id: reBuildNeeded - repeat: true + id: ensureNotFuturetime interval: 1000 + repeat: false 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: + Rectangle { - 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) + width: 1 + height: parent.height + anchors.right: addBlockBtn.left + color: "#ededed" } - 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) + ScenarioButton { + id: addBlockBtn + text: qsTr("Add Block..") + anchors.left: addTransaction.right + roundLeft: false + roundRight: true + onClicked: { - var lastBlock = model.blocks[model.blocks.length - 1] - if (lastBlock.status === "pending") + if (ensureNotFuturetime.running) + return + if (clientModel.mining || clientModel.running) + return + if (model.blocks.length > 0) { - ensureNotFuturetime.start() - clientModel.mine() + var lastBlock = model.blocks[model.blocks.length - 1] + if (lastBlock.status === "pending") + { + ensureNotFuturetime.start() + clientModel.mine() + } + else + addNewBlock() } else addNewBlock() + } - else - addNewBlock() - } + function addNewBlock() + { + var block = projectModel.stateListModel.createEmptyBlock() + model.blocks.push(block) + blockModel.appendBlock(block) + } + width: 100 + height: 30 - function addNewBlock() - { - var block = projectModel.stateListModel.createEmptyBlock() - model.blocks.push(block) - blockModel.appendBlock(block) + buttonShortcut: "" + sourceImg: "qrc:/qml/img/addblock@2x.png" } - Layout.preferredWidth: 100 - Layout.preferredHeight: 30 - buttonShortcut: "" - sourceImg: "qrc:/qml/img/addblock@2x.png" } + Connections { target: clientModel @@ -412,7 +457,6 @@ ColumnLayout { return; } } - // tr is not in the list. var itemTr = TransactionHelper.defaultTransaction() itemTr.saveStatus = false @@ -438,7 +482,7 @@ ColumnLayout { ScenarioButton { id: newAccount - text: qsTr("New Account") + text: qsTr("New Account..") onClicked: { model.accounts.push(projectModel.stateListModel.newAccount("1000000", QEther.Ether)) } @@ -446,6 +490,8 @@ ColumnLayout { Layout.preferredHeight: 30 buttonShortcut: "" sourceImg: "qrc:/qml/img/newaccounticon@2x.png" + roundLeft: true + roundRight: true } } } diff --git a/mix/qml/Ether.qml b/mix/qml/Ether.qml index 7a059e04d..29323642a 100644 --- a/mix/qml/Ether.qml +++ b/mix/qml/Ether.qml @@ -54,6 +54,7 @@ RowLayout { { id: units visible: displayUnitSelection; + implicitWidth: 145 onCurrentTextChanged: { if (value) diff --git a/mix/qml/MainContent.qml b/mix/qml/MainContent.qml index de19baf35..7f180a899 100644 --- a/mix/qml/MainContent.qml +++ b/mix/qml/MainContent.qml @@ -31,6 +31,7 @@ Rectangle { property alias codeEditor: codeEditor property bool webViewHorizontal: codeWebSplitter.orientation === Qt.Vertical //vertical splitter positions elements vertically, splits screen horizontally property bool firstCompile: true + property int scenarioMinWidth: 590 Connections { target: codeModel @@ -110,6 +111,7 @@ Rectangle { property alias webHeight: webPreview.height property alias showProjectView: projectList.visible property bool runOnProjectLoad: true + property int scenarioMinWidth: scenarioMinWidth } ColumnLayout @@ -205,7 +207,7 @@ Rectangle { visible: false; Layout.fillHeight: true Keys.onEscapePressed: visible = false - Layout.minimumWidth: 650 + Layout.minimumWidth: scenarioMinWidth anchors.right: parent.right } @@ -215,7 +217,7 @@ Rectangle { visible: false Layout.fillHeight: true Keys.onEscapePressed: visible = false - Layout.minimumWidth: 650 + Layout.minimumWidth: scenarioMinWidth anchors.right: parent.right } @@ -224,10 +226,9 @@ Rectangle { onDebugDataReady: { scenarioExe.visible = false debugPanel.visible = true + debugPanel.width = scenarioExe.width if (scenarioExe.bc.debugTrRequested) - { debugPanel.setTr(scenarioExe.bc.model.blocks[scenarioExe.bc.debugTrRequested[0]].transactions[scenarioExe.bc.debugTrRequested[1]]) - } } } @@ -236,6 +237,7 @@ Rectangle { onPanelClosed: { debugPanel.visible = false scenarioExe.visible = true + scenarioExe.width = debugPanel.width } } } diff --git a/mix/qml/QAddressView.qml b/mix/qml/QAddressView.qml index 4781d092b..56aefcf3e 100644 --- a/mix/qml/QAddressView.qml +++ b/mix/qml/QAddressView.qml @@ -2,14 +2,14 @@ import QtQuick 2.0 import QtQuick.Controls 1.3 import QtQuick.Controls.Styles 1.3 -Item +Row { property alias value: textinput.text property alias accountRef: ctrModel property string subType property bool readOnly property alias currentIndex: trCombobox.currentIndex - property alias currentText: textinput.text + property alias displayInput: textInputRect.visible property variant accounts signal indexChanged() id: editRoot @@ -22,7 +22,7 @@ Item } function currentValue() { - return currentText; + return value; } function currentType() @@ -38,7 +38,6 @@ Item function load() { accountRef.clear(); - accountRef.append({"itemid": " - "}); if (subType === "contract" || subType === "address") { var trCr = 0; @@ -52,7 +51,7 @@ Item if (i > transactionIndex) break; var tr = blockChainPanel.model.blocks[k].transactions[i] - if (tr.functionId === tr.contractId /*&& (dec[1] === tr.contractId || item.subType === "address")*/) + if (tr.functionId === tr.contractId) { accountRef.append({ "itemid": tr.contractId + " - " + trCr, "value": "<" + tr.contractId + " - " + trCr + ">", "type": "contract" }); trCr++; @@ -87,6 +86,7 @@ Item } trCombobox.currentIndex = 0; } + trCombobox.update() } function select(address) @@ -102,10 +102,10 @@ Item } Rectangle { - anchors.fill: parent radius: 4 anchors.verticalCenter: parent.verticalCenter height: 20 + id: textInputRect TextInput { id: textinput text: value @@ -141,12 +141,12 @@ Item property bool selected: false id: trCombobox model: ctrModel + width: 350 textRole: "itemid" - height: 20 anchors.verticalCenter: parent.verticalCenter - anchors.left: textinput.parent.right - anchors.leftMargin: 3 - onCurrentIndexChanged: { + + function update() + { trCombobox.selected = false; if (currentText === "") return; @@ -164,5 +164,9 @@ Item } indexChanged(); } + + onCurrentIndexChanged: { + update() + } } } diff --git a/mix/qml/QBoolTypeView.qml b/mix/qml/QBoolTypeView.qml index a95c12040..12c932762 100644 --- a/mix/qml/QBoolTypeView.qml +++ b/mix/qml/QBoolTypeView.qml @@ -21,16 +21,19 @@ Item value = value === "true" ? "1" : value value = value === "false" ? "0" : value; + var setValue = "1" if (value === "") - boolCombo.currentIndex = parseInt(defaultValue); + setValue = parseInt(defaultValue); else - boolCombo.currentIndex = parseInt(value); + setValue = parseInt(value); + boolCombo.checked = setValue === "1" ? true: false boolCombo.enabled = !readOnly; } Rectangle { + color: "transparent" anchors.fill: parent - ComboBox + CheckBox { property bool inited; Component.onCompleted: @@ -41,17 +44,13 @@ Item id: boolCombo anchors.fill: parent - onCurrentIndexChanged: + onCheckedChanged: { if (inited) - value = comboModel.get(currentIndex).value; - } - model: ListModel - { - id: comboModel - ListElement { text: qsTr("False"); value: "0" } - ListElement { text: qsTr("True"); value: "1" } + value = checked ? "1" : "0" + } + text: qsTr("True") } } } diff --git a/mix/qml/QHashTypeView.qml b/mix/qml/QHashTypeView.qml index ee5848b3a..6811dd43f 100644 --- a/mix/qml/QHashTypeView.qml +++ b/mix/qml/QHashTypeView.qml @@ -13,22 +13,15 @@ Item id: boldFont } - Rectangle { - anchors.fill: parent - radius: 4 - TextInput { - id: textinput - text: value + TextInput { + id: textinput + text: value + wrapMode: Text.WrapAnywhere + MouseArea { + id: mouseArea anchors.fill: parent - wrapMode: Text.WrapAnywhere - clip: true - font.family: boldFont.name - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - onClicked: textinput.forceActiveFocus() - } + hoverEnabled: true + onClicked: textinput.forceActiveFocus() } } } diff --git a/mix/qml/QIntTypeView.qml b/mix/qml/QIntTypeView.qml index ec54d6409..6bee54a1f 100644 --- a/mix/qml/QIntTypeView.qml +++ b/mix/qml/QIntTypeView.qml @@ -1,35 +1,26 @@ import QtQuick 2.0 - +import QtQuick.Controls 1.1 Item { property alias value: textinput.text property alias readOnly: textinput.readOnly id: editRoot - width: readOnly ? textinput.implicitWidth : 150 - + width: 200 DebuggerPaneStyle { id: dbgStyle } - Rectangle { - anchors.fill: parent - radius: 4 - TextInput { - anchors.verticalCenter: parent.verticalCenter - id: textinput - font.family: dbgStyle.general.basicFont - clip: true - selectByMouse: true - text: value + TextField { + anchors.verticalCenter: parent.verticalCenter + id: textinput + selectByMouse: true + text: value + implicitWidth: 200 + MouseArea { + id: mouseArea anchors.fill: parent - font.pointSize: dbgStyle.general.basicFontSize - color: dbgStyle.general.basicColor - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - onClicked: textinput.forceActiveFocus() - } + hoverEnabled: true + onClicked: textinput.forceActiveFocus() } } } diff --git a/mix/qml/QStringTypeView.qml b/mix/qml/QStringTypeView.qml index c42e65654..25831cb00 100644 --- a/mix/qml/QStringTypeView.qml +++ b/mix/qml/QStringTypeView.qml @@ -1,4 +1,5 @@ import QtQuick 2.0 +import QtQuick.Controls 1.1 Item { @@ -11,25 +12,16 @@ Item id: dbgStyle } - Rectangle { - anchors.fill: parent - radius: 4 - TextInput { - anchors.verticalCenter: parent.verticalCenter - id: textinput - font.family: dbgStyle.general.basicFont - clip: true - selectByMouse: true - text: value + TextField { + anchors.verticalCenter: parent.verticalCenter + id: textinput + selectByMouse: true + text: value + MouseArea { + id: mouseArea anchors.fill: parent - font.pointSize: dbgStyle.general.basicFontSize - color: dbgStyle.general.basicColor - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - onClicked: textinput.forceActiveFocus() - } + hoverEnabled: true + onClicked: textinput.forceActiveFocus() } } } diff --git a/mix/qml/ScenarioButton.qml b/mix/qml/ScenarioButton.qml index 4dd7bc53f..d4beaefaa 100644 --- a/mix/qml/ScenarioButton.qml +++ b/mix/qml/ScenarioButton.qml @@ -2,6 +2,7 @@ import QtQuick 2.2 import QtQuick.Controls 1.1 import QtQuick.Layouts 1.0 import QtQuick.Controls.Styles 1.1 +import QtGraphicalEffects 1.0 Rectangle { id: buttonActionContainer @@ -9,15 +10,68 @@ Rectangle { property string buttonShortcut property string sourceImg property string fillColor + property alias roundLeft: left.visible + property alias roundRight: right.visible signal clicked + function startBlinking() + { + if (!blinkTimer.running) + blinkTimer.start() + } + + function stopBlinking() + { + blinkTimer.stop() + } + + Rectangle + { + id: left + width: 10 + height: parent.height + anchors.left: parent.left + anchors.leftMargin: -8 + radius: 15 + } + Rectangle { id: contentRectangle anchors.fill: parent - border.color: "#cccccc" - border.width: 1 - radius: 4 - color: parent.fillColor ? parent.fillColor : "white" + color: "white" + property variant colorGradient: ["#FFFFFF", "#FFFEFC", "#FFFDF9", "#FFFCF7", "#FFFBF4", "#FFFAF2", "#FFF9EF", "#FFF8EC", "#FFF7EA", "#FFF6E7", "#FFF5E5", "#FFF5E2", "#FFF4E0", "#FFF3DD", "#FFF2DA", "#FFF1D8", "#FFF0D5", "#FFEFD3", "#FFEED0", "#FFEDCE", "#FFECCB", "#FFEBC8", "#FFEBC6", "#FFEAC3", "#FFE9C1", "#FFE8BE", "#FFE7BC", "#FFE6B9", "#FFE5B6", "#FFE4B4", "#FFE3B1", "#FFE2AF", "#FFE1AC", "#FFE1AA", "#FFE0A7", "#FFDFA4", "#FFDEA2", "#FFDD9F", "#FFDC9D", "#FFDB9A", "#FFDA97", "#FFD995", "#FFD892", "#FFD790", "#FFD78D", "#FFD68B", "#FFD588", "#FFD485", "#FFD383", "#FFD280", "#FFD17E", "#FFD07B", "#FFCF79", "#FFCE76", "#FFCD73", "#FFCD71", "#FFCC6E", "#FFCB6C", "#FFCA69", "#FFC967", "#FFC864", "#FFC761", "#FFC65F", "#FFC55C", "#FFC45A", "#FFC357", "#FFC355", "#FFC252", "#FFC14F", "#FFC04D", "#FFBF4A", "#FFBE48", "#FFBD45", "#FFBC42", "#FFBB40", "#FFBA3D", "#FFB93B", "#FFB938", "#FFB836", "#FFB733", "#FFB630", "#FFB52E", "#FFB42B", "#FFB329", "#FFB226", "#FFB124", "#FFB021", "#FFAF1E", "#FFAF1C", "#FFAE19", "#FFAD17", "#FFAC14", "#FFAB12", "#FFAA0F", "#FFA90C", "#FFA80A", "#FFA707", "#FFA605", "#FFA502", "#FFA500"] + + Timer + { + id: blinkTimer + repeat: true + interval: 40 + running: false + property int index: 0 + property int direction: 1 + onTriggered: { + index = index + direction + var color = parent.colorGradient[index] + left.color = color + right.color = color + parent.color = parent.colorGradient[index] + if (index >= parent.colorGradient.length - 1) + direction = -1 + else if (index <= 0) + direction = 1 + } + onRunningChanged: { + if (!running) + { + left.color = "white" + right.color = "white" + parent.color = "white" + index = 0 + direction = 1 + } + } + } + Image { id: debugImage anchors { @@ -25,12 +79,11 @@ Rectangle { right: parent.right top: parent.top bottom: parent.bottom - bottomMargin: debugImg.pressed ? 0 : 2; + bottomMargin: debugImg.pressed ? -2 : 0; topMargin: debugImg.pressed ? 2 : 0; } source: sourceImg fillMode: Image.PreserveAspectFit - height: 30 } Button { @@ -53,12 +106,22 @@ Rectangle { } } + Rectangle + { + id: right + width: 10 + height: parent.height + anchors.left: contentRectangle.right + anchors.leftMargin: -8 + radius: 15 + } + Rectangle { anchors.top: contentRectangle.bottom anchors.topMargin: 15 width: parent.width - Text + Label { text: buttonActionContainer.text anchors.centerIn: parent diff --git a/mix/qml/ScenarioExecution.qml b/mix/qml/ScenarioExecution.qml index bc872bff7..3e9d8e089 100644 --- a/mix/qml/ScenarioExecution.qml +++ b/mix/qml/ScenarioExecution.qml @@ -28,14 +28,23 @@ Rectangle { spacing: 10 ScenarioLoader { - height: 70 + height: 100 width: parent.width id: loader } + Connections + { + target: blockChain + onChainChanged: + { + loader.needSaveOrReload() + } + } + Rectangle { - width: parent.width + width: parent.parent.width height: 1 color: "#cccccc" } @@ -43,7 +52,8 @@ Rectangle { Connections { target: loader - onLoaded: { + onLoaded: + { blockChain.load(scenario) } } diff --git a/mix/qml/ScenarioLoader.qml b/mix/qml/ScenarioLoader.qml index 93f4f059b..bc26b103d 100644 --- a/mix/qml/ScenarioLoader.qml +++ b/mix/qml/ScenarioLoader.qml @@ -10,166 +10,329 @@ import "js/Debugger.js" as Debugger import "js/ErrorLocationFormater.js" as ErrorLocationFormater import "." -RowLayout +ColumnLayout { + id: blockChainSelector signal restored(variant scenario) signal saved(variant scenario) signal duplicated(variant scenario) signal loaded(variant scenario) + signal renamed(variant scenario) spacing: 0 function init() { scenarioList.load() } - id: blockChainSelector - - Dialog { - id: newStateWin - modality: Qt.ApplicationModal - title: qsTr("New Project"); - - width: 320 - height: 120 + function needSaveOrReload() + { + editStatus.visible = true + } - visible: false + Rectangle + { + Layout.fillWidth: true + Layout.preferredHeight: 30 + color: "transparent" + Rectangle + { + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + color: "transparent" + Label + { + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + id: scenarioName + font.bold: true + } - contentItem: Rectangle { - anchors.fill: parent - anchors.margins: 10 - RowLayout { + TextInput + { + id: scenarioNameEdit + visible: false anchors.verticalCenter: parent.verticalCenter - Text { - text: qsTr("Name:") + anchors.horizontalCenter: parent.horizontalCenter + Keys.onEnterPressed: + { + save() } - Rectangle + function edit() { - Layout.preferredWidth: 250 - Layout.preferredHeight: parent.height - border.width: 1 - border.color: "#cccccc" - TextInput - { - anchors.fill: parent - id: stateName - } + editIconRect.anchors.left = scenarioNameEdit.right + editStatus.parent.anchors.left = scenarioNameEdit.right + scenarioNameEdit.forceActiveFocus() + } + + function save() + { + editIconRect.anchors.left = scenarioName.right + editStatus.parent.anchors.left = scenarioName.right + scenarioName.text = scenarioNameEdit.text + scenarioName.visible = true + scenarioNameEdit.visible = false + projectModel.stateListModel.getState(scenarioList.currentIndex).title = scenarioName.text + projectModel.saveProjectFile() + saved(state) + scenarioList.model.get(scenarioList.currentIndex).title = scenarioName.text + scenarioList.currentIndex = scenarioList.currentIndex + renamed(projectModel.stateListModel.getState(scenarioList.currentIndex)) } } - RowLayout + + Connections { - anchors.bottom: parent.bottom - anchors.right: parent.right; - function acceptAndClose() + target: blockChainSelector + onLoaded: { - var item = projectModel.stateListModel.createDefaultState(); - item.title = stateName.text - projectModel.stateListModel.appendState(item) - projectModel.stateListModel.save() - close() - scenarioList.currentIndex = projectModel.stateListModel.count - 1 + scenarioName.text = scenario.title + scenarioNameEdit.text = scenario.title } + } - function close() - { - newStateWin.close() - stateName.text = "" + Rectangle + { + anchors.left: scenarioName.right + anchors.top: scenarioName.top + anchors.leftMargin: 2 + Layout.preferredWidth: 20 + Text { + id: editStatus + text: "*" + visible: false } + } - Button { - id: okButton; - enabled: stateName.text !== "" - text: qsTr("OK"); - onClicked: { - parent.acceptAndClose(); + Rectangle + { + id: editIconRect + anchors.left: scenarioName.right + anchors.leftMargin: 15 + Image { + source: "qrc:/qml/img/edit.png" + width: 10 + fillMode: Image.PreserveAspectFit + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + MouseArea + { + anchors.fill: parent + onClicked: + { + scenarioName.visible = !scenarioName.visible + scenarioNameEdit.visible = !scenarioNameEdit.visible + if (!scenarioNameEdit.visible) + scenarioNameEdit.save() + else + scenarioNameEdit.edit() + + } } } - Button { - text: qsTr("Cancel"); - onClicked: parent.close(); - } } } } - ComboBox + RowLayout { - id: scenarioList - model: projectModel.stateListModel - textRole: "title" - onCurrentIndexChanged: - { - restoreScenario.restore() - } + Layout.preferredWidth: 560 + anchors.horizontalCenter: parent.horizontalCenter + Layout.preferredHeight: 50 + spacing: 0 - function load() + Row { - var state = projectModel.stateListModel.getState(currentIndex) - loaded(state) - } - } + Layout.preferredWidth: 100 * 5 + Layout.preferredHeight: 50 + spacing: 15 - 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() + Rectangle { - var state = projectModel.stateListModel.reloadStateFromFromProject(scenarioList.currentIndex) - restored(state) - loaded(state) - } - } + color: "transparent" + width: 251 + height: 30 + Rectangle + { + width: 10 + height: parent.height + anchors.right: scenarioList.left + anchors.rightMargin: -8 + radius: 15 + } - ScenarioButton { - id: saveScenario - text: qsTr("Save") - onClicked: { - projectModel.saveProjectFile() - saved(state) - } - width: 100 - height: 30 - buttonShortcut: "" - sourceImg: "qrc:/qml/img/saveicon@2x.png" - } + ComboBox + { + id: scenarioList + model: projectModel.stateListModel + textRole: "title" + height: parent.height + width: 150 + onCurrentIndexChanged: + { + restoreScenario.restore() + } - ScenarioButton - { - id: duplicateScenario - text: qsTr("Duplicate") - onClicked: { - projectModel.stateListModel.duplicateState(scenarioList.currentIndex) - duplicated(state) + function load() + { + var state = projectModel.stateListModel.getState(currentIndex) + loaded(state) + } + + style: ComboBoxStyle { + background: Rectangle { + color: "white" + anchors.fill: parent + } + label: Rectangle { + anchors.fill: parent + color: "white" + Label { + id: comboLabel + maximumLineCount: 1 + elide: Text.ElideRight + width: parent.width + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + text: { + if (projectModel.stateListModel.getState(scenarioList.currentIndex)) + return projectModel.stateListModel.getState(scenarioList.currentIndex).title + else + return "" + } + Connections { + target: blockChainSelector + onLoaded: { + comboLabel.text = projectModel.stateListModel.getState(scenarioList.currentIndex).title + } + onRenamed: { + comboLabel.text = scenario.title + } + } + } + } + } + } + + Rectangle + { + width: 1 + height: parent.height + anchors.right: addScenario.left + color: "#ededed" + } + + ScenarioButton { + id: addScenario + anchors.left: scenarioList.right + width: 100 + height: parent.height + buttonShortcut: "" + sourceImg: "qrc:/qml/img/restoreicon@2x.png" + onClicked: { + var item = projectModel.stateListModel.createDefaultState(); + item.title = qsTr("New Scenario") + projectModel.stateListModel.appendState(item) + projectModel.stateListModel.save() + scenarioList.currentIndex = projectModel.stateListModel.count - 1 + scenarioNameEdit.edit() + } + text: qsTr("New..") + roundRight: true + roundLeft: false + } } - 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() + + Rectangle + { + width: 100 * 3 + height: 30 + color: "transparent" + + Rectangle + { + width: 10 + height: parent.height + anchors.right: restoreScenario.left + anchors.rightMargin: -4 + radius: 15 + } + + ScenarioButton { + id: restoreScenario + width: 100 + height: parent.height + buttonShortcut: "" + sourceImg: "qrc:/qml/img/restoreicon@2x.png" + onClicked: { + restore() + } + text: qsTr("Restore") + function restore() + { + var state = projectModel.stateListModel.reloadStateFromFromProject(scenarioList.currentIndex) + if (state) + { + editStatus.visible = false + restored(state) + loaded(state) + } + } + roundRight: false + roundLeft: true + } + + + Rectangle + { + width: 1 + height: parent.height + anchors.right: saveScenario.left + color: "#ededed" + } + + ScenarioButton { + id: saveScenario + anchors.left: restoreScenario.right + text: qsTr("Save") + onClicked: { + projectModel.saveProjectFile() + saved(state) + } + width: 100 + height: parent.height + buttonShortcut: "" + sourceImg: "qrc:/qml/img/saveicon@2x.png" + roundRight: false + roundLeft: false + } + + Rectangle + { + width: 1 + height: parent.height + anchors.right: duplicateScenario.left + color: "#ededed" + } + + ScenarioButton + { + id: duplicateScenario + anchors.left: saveScenario.right + text: qsTr("Duplicate") + onClicked: { + projectModel.stateListModel.duplicateState(scenarioList.currentIndex) + duplicated(state) + } + width: 100 + height: parent.height + buttonShortcut: "" + sourceImg: "qrc:/qml/img/duplicateicon@2x.png" + roundRight: true + roundLeft: false + } } - text: qsTr("New") } } - } diff --git a/mix/qml/StructView.qml b/mix/qml/StructView.qml index 6b9edc755..bd2cbf598 100644 --- a/mix/qml/StructView.qml +++ b/mix/qml/StructView.qml @@ -13,58 +13,40 @@ Column property int transactionIndex property string context Layout.fillWidth: true - spacing: 0 - - DebuggerPaneStyle { - id: dbgStyle - } - + spacing: 5 Repeater { id: repeater visible: model.length > 0 - Layout.fillWidth: true - RowLayout { id: row - height: 20 + (members[index].type.category === QSolidityType.Struct ? (20 * members[index].type.members.length) : 0) + height: 30 + (members[index].type.category === QSolidityType.Struct ? (30 * members[index].type.members.length) : 0) Layout.fillWidth: true - DefaultLabel { - height: 20 - id: typeLabel - text: modelData.type.name - anchors.verticalCenter: parent.verticalCenter - font.family: dbgStyle.general.basicFont - color: dbgStyle.general.basicColor - font.pointSize: dbgStyle.general.basicFontSize - } - - DefaultLabel { - height: 20 - id: nameLabel - text: modelData.name - anchors.verticalCenter: parent.verticalCenter - font.family: dbgStyle.general.basicFont - color: dbgStyle.general.basicColor - font.pointSize: dbgStyle.general.basicFontSize - } + Rectangle + { + Layout.preferredWidth: 150 + Row + { + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + Label { + id: nameLabel + text: modelData.name + } - DefaultLabel { - height: 20 - id: equalLabel - text: "=" - anchors.verticalCenter: parent.verticalCenter - font.family: dbgStyle.general.basicFont - color: dbgStyle.general.basicColor - font.pointSize: dbgStyle.general.basicFontSize + Label { + id: typeLabel + text: " (" + modelData.type.name + ")" + font.italic: true + font.weight: Font.Light + } + } } Loader { id: typeLoader - height: 20 - anchors.verticalCenter: parent.verticalCenter sourceComponent: { var t = modelData.type.category; diff --git a/mix/qml/TransactionDialog.qml b/mix/qml/TransactionDialog.qml index 287ba08c2..f4aa9a5f0 100644 --- a/mix/qml/TransactionDialog.qml +++ b/mix/qml/TransactionDialog.qml @@ -7,12 +7,13 @@ import QtQuick.Controls.Styles 1.3 import org.ethereum.qml.QEther 1.0 import "js/TransactionHelper.js" as TransactionHelper import "js/InputValidator.js" as InputValidator +import "js/NetworkDeployment.js" as NetworkDeployment import "." Dialog { id: modalTransactionDialog modality: Qt.ApplicationModal - width: 570 + width: 580 height: 500 visible: false title: qsTr("Edit Transaction") @@ -22,7 +23,7 @@ Dialog { property alias gasAuto: gasAutoCheck.checked; property alias gasPrice: gasPriceField.value; property alias transactionValue: valueField.value; - property string contractId: contractComboBox.currentValue(); + property string contractId: contractCreationComboBox.currentValue(); property alias functionId: functionComboBox.currentText; property var paramValues; property var paramsModel: []; @@ -30,21 +31,16 @@ Dialog { property alias stateAccounts: senderComboBox.model property bool saveStatus signal accepted; - + property int rowWidth: 500 StateDialogStyle { id: transactionDialogStyle } function open(index, blockIdx, item) { - rowFunction.visible = !useTransactionDefaultValue; - rowValue.visible = !useTransactionDefaultValue; - rowGas.visible = !useTransactionDefaultValue; - rowGasPrice.visible = !useTransactionDefaultValue; - transactionIndex = index blockIndex = blockIdx - typeLoader.transactionIndex = index - typeLoader.blockIndex = blockIdx + paramScroll.transactionIndex = index + paramScroll.blockIndex = blockIdx saveStatus = item.saveStatus gasValueEdit.gasValue = item.gas; gasAutoCheck.checked = item.gasAuto ? true : false; @@ -52,48 +48,20 @@ Dialog { valueField.value = item.value; var contractId = item.contractId; var functionId = item.functionId; - rowFunction.visible = true; paramValues = item.parameters !== undefined ? item.parameters : {}; if (item.sender) senderComboBox.select(item.sender); - contractsModel.clear(); - var contractIndex = -1; - var contracts = codeModel.contracts; - for (var c in contracts) { - contractsModel.append({ cid: c, text: contracts[c].contract.name }); - if (contracts[c].contract.name === contractId) - contractIndex = contractsModel.count - 1; - } - if (contractIndex == -1 && contractsModel.count > 0) - contractIndex = 0; //@todo suggest unused contract - contractComboBox.currentIndex = contractIndex; + trTypeCreate.checked = item.isContractCreation + trTypeSend.checked = !item.isFunctionCall + trTypeExecute.checked = item.isFunctionCall && !item.isContractCreation - recipients.accounts = senderComboBox.model; - recipients.subType = "address"; - recipients.load(); - recipients.init(); - recipients.select(contractId); - - if (item.isContractCreation) - loadFunctions(contractComboBox.currentValue()); - else - loadFunctions(contractFromToken(recipients.currentValue())) - selectFunction(functionId); - - trType.checked = item.isContractCreation - trType.init(); - - paramsModel = []; - if (item.isContractCreation) - loadCtorParameters(); - else - loadParameters(); + load(item.isContractCreation, item.isFunctionCall, functionId, contractId) + estimatedGas.updateView() visible = true; - valueField.focus = true; } function loadCtorParameters(contractId) @@ -111,12 +79,12 @@ Dialog { function loadFunctions(contractId) { functionsModel.clear(); - functionsModel.append({ text: " - " }); var contract = codeModel.contracts[contractId]; if (contract) { var functions = codeModel.contracts[contractId].contract.functions; for (var f = 0; f < functions.length; f++) { - functionsModel.append({ text: functions[f].name }); + if (functions[f].name !== contractId) + functionsModel.append({ text: functions[f].name }); } } } @@ -156,9 +124,9 @@ Dialog { function loadParameters() { paramsModel = [] if (functionComboBox.currentIndex >= 0 && functionComboBox.currentIndex < functionsModel.count) { - var contract = codeModel.contracts[contractFromToken(recipients.currentValue())]; + var contract = codeModel.contracts[contractFromToken(contractCreationComboBox.currentValue())]; if (contract) { - var func = contract.contract.functions[functionComboBox.currentIndex - 1]; + var func = contract.contract.functions[functionComboBox.currentIndex + 1]; if (func) { var parameters = func.parameters; for (var p = 0; p < parameters.length; p++) @@ -171,13 +139,11 @@ Dialog { function initTypeLoader() { - typeLoader.value = {} - typeLoader.members = [] - typeLoader.value = paramValues; - typeLoader.members = paramsModel; - paramLabel.visible = paramsModel.length > 0; - paramScroll.visible = paramsModel.length > 0; - modalTransactionDialog.height = (paramsModel.length > 0 ? 500 : 300); + paramScroll.value = {} + paramScroll.members = [] + paramScroll.value = paramValues; + paramScroll.members = paramsModel; + paramScroll.updateView() } function acceptAndClose() @@ -213,16 +179,16 @@ Dialog { item.functionId = transactionDialog.functionId; } - item.isContractCreation = trType.checked; + item.isContractCreation = trTypeCreate.checked; if (item.isContractCreation) item.functionId = item.contractId; - item.isFunctionCall = item.functionId !== " - "; + item.isFunctionCall = trTypeExecute.checked if (!item.isContractCreation) { - item.contractId = recipients.currentText; - item.label = item.contractId + " " + item.functionId; - if (recipients.current().type === "address") + item.contractId = recipientsAccount.currentValue(); + item.label = contractFromToken(item.contractId) + "." + item.functionId + "()"; + if (recipientsAccount.current().type === "address") { item.functionId = ""; item.isFunctionCall = false; @@ -230,8 +196,9 @@ Dialog { } else { + item.isFunctionCall = true item.functionId = item.contractId; - item.label = qsTr("Deploy") + " " + item.contractId; + item.label = item.contractId + "." + item.contractId + "()"; } item.saveStatus = saveStatus item.sender = senderComboBox.model[senderComboBox.currentIndex].secret; @@ -246,187 +213,360 @@ Dialog { return token; } + function load(isContractCreation, isFunctionCall, functionId, contractId) + { + if (!isContractCreation) + { + contractCreationComboBox.visible = false + recipientsAccount.visible = true + recipientsAccount.accounts = senderComboBox.model; + amountLabel.text = qsTr("Amount") + if (!isFunctionCall) + recipientsAccount.subType = "address" + else + recipientsAccount.subType = "contract"; + recipientsAccount.load(); + recipientsAccount.init(); + if (contractId) + recipientsAccount.select(contractId); + if (functionId) + selectFunction(functionId); + if (isFunctionCall) + { + labelRecipient.text = qsTr("Recipient Contract") + functionRect.show() + loadFunctions(contractFromToken(recipientsAccount.currentValue())) + loadParameters(); + paramScroll.updateView() + } + else + { + paramsModel = [] + paramScroll.updateView() + labelRecipient.text = qsTr("Recipient Account") + functionRect.hide() + } + } + else + { + //contract creation + contractsModel.clear(); + var contractIndex = -1; + var contracts = codeModel.contracts; + for (var c in contracts) { + contractsModel.append({ cid: c, text: contracts[c].contract.name }); + if (contracts[c].contract.name === contractId) + contractIndex = contractsModel.count - 1; + } + + if (contractIndex == -1 && contractsModel.count > 0) + contractIndex = 0; //@todo suggest unused contract + contractCreationComboBox.currentIndex = contractIndex; + contractCreationComboBox.visible = true + labelRecipient.text = qsTr("Contract") + amountLabel.text = qsTr("Endownment") + functionRect.hide() + recipientsAccount.visible = false + loadCtorParameters(contractCreationComboBox.currentValue()); + paramScroll.updateView() + } + } + contentItem: Rectangle { + id: containerRect color: transactionDialogStyle.generic.backgroundColor - ColumnLayout { + anchors.fill: parent + ScrollView + { + anchors.top: parent.top anchors.fill: parent ColumnLayout { - anchors.fill: parent - anchors.margins: 10 - - ColumnLayout { - id: dialogContent - anchors.top: parent.top - spacing: 10 - RowLayout + Layout.preferredWidth: rowWidth + anchors.top: parent.top + anchors.topMargin: 10 + anchors.left: parent.left + width: 500 + anchors.leftMargin: + { + return (containerRect.width - 530) /2 + } + + RowLayout + { + Rectangle { - id: rowSender - Layout.fillWidth: true - height: 150 - DefaultLabel { - Layout.preferredWidth: 75 - text: qsTr("Sender") + Layout.preferredWidth: 150 + Label { + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + text: qsTr("Sender Account") } - ComboBox { + } - function select(secret) - { - for (var i in model) - if (model[i].secret === secret) - { - currentIndex = i; - break; - } - } + ComboBox { + function select(secret) + { + for (var i in model) + if (model[i].secret === secret) + { + currentIndex = i; + break; + } + } + Layout.preferredWidth: 350 + id: senderComboBox + currentIndex: 0 + textRole: "name" + editable: false + } + } - id: senderComboBox - Layout.preferredWidth: 350 - currentIndex: 0 - textRole: "name" - editable: false + RowLayout + { + Rectangle + { + Layout.preferredWidth: 150 + Layout.preferredHeight: 80 + color: "transparent" + Label + { + anchors.verticalCenter: parent.verticalCenter + anchors.top: parent.top + anchors.right: parent.right + text: qsTr("Type of Transaction") } } - RowLayout + Column { - id: rowIsContract - Layout.fillWidth: true - height: 150 - CheckBox { - id: trType - onCheckedChanged: - { - init(); + Layout.preferredWidth: 350 + Layout.preferredHeight: 90 + ExclusiveGroup { + id: rbbuttonList + onCurrentChanged: { + if (current) + { + if (current.objectName === "trTypeSend") + { + recipientsAccount.visible = true + contractCreationComboBox.visible = false + modalTransactionDialog.load(false, false) + } + else if (current.objectName === "trTypeCreate") + { + contractCreationComboBox.visible = true + recipientsAccount.visible = false + modalTransactionDialog.load(true, true) + } + else if (current.objectName === "trTypeExecute") + { + recipientsAccount.visible = true + contractCreationComboBox.visible = false + modalTransactionDialog.load(false, true) + } + } } + } - function init() - { - rowFunction.visible = !checked; - rowContract.visible = checked; - rowRecipient.visible = !checked; - paramLabel.visible = checked; - paramScroll.visible = checked; - functionComboBox.enabled = !checked; - if (checked) - loadCtorParameters(contractComboBox.currentValue()); - } + RadioButton { + id: trTypeSend + objectName: "trTypeSend" + exclusiveGroup: rbbuttonList + height: 30 + text: qsTr("Send ether to account") - text: qsTr("is contract creation") - checked: true + } + + RadioButton { + id: trTypeCreate + objectName: "trTypeCreate" + exclusiveGroup: rbbuttonList + height: 30 + text: qsTr("Create Contract") + } + + RadioButton { + id: trTypeExecute + objectName: "trTypeExecute" + exclusiveGroup: rbbuttonList + height: 30 + text: qsTr("Execute Contract") } } + } - RowLayout + RowLayout + { + Rectangle { - id: rowRecipient - Layout.fillWidth: true - height: 150 - DefaultLabel { - Layout.preferredWidth: 75 - text: qsTr("Recipient") + Layout.preferredWidth: 150 + Label { + id: labelRecipient + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + text: qsTr("Recipient Account") } + } - QAddressView + QAddressView + { + id: recipientsAccount + displayInput: false + onIndexChanged: { - id: recipients - onIndexChanged: - { - rowFunction.visible = current().type === "contract"; - paramLabel.visible = current().type === "contract"; - paramScroll.visible = current().type === "contract"; - if (!rowIsContract.checked) - loadFunctions(contractFromToken(recipients.currentValue())) - } + if (rbbuttonList.current.objectName === "trTypeExecute") + loadFunctions(contractFromToken(currentValue())) } } - RowLayout - { - id: rowContract - Layout.fillWidth: true - height: 150 - DefaultLabel { - Layout.preferredWidth: 75 - text: qsTr("Contract") + ComboBox { + id: contractCreationComboBox + function currentValue() { + return (currentIndex >=0 && currentIndex < contractsModel.count) ? contractsModel.get(currentIndex).cid : ""; } - ComboBox { - id: contractComboBox - function currentValue() { - return (currentIndex >=0 && currentIndex < contractsModel.count) ? contractsModel.get(currentIndex).cid : ""; - } - Layout.preferredWidth: 350 - currentIndex: -1 - textRole: "text" - editable: false - model: ListModel { - id: contractsModel - } - onCurrentIndexChanged: { - loadCtorParameters(currentValue()); - } + Layout.preferredWidth: 350 + currentIndex: -1 + textRole: "text" + editable: false + model: ListModel { + id: contractsModel + } + onCurrentIndexChanged: { + loadCtorParameters(currentValue()); } } + } - RowLayout + RowLayout + { + Rectangle { - id: rowFunction - Layout.fillWidth: true - height: 150 - DefaultLabel { - Layout.preferredWidth: 75 + Layout.preferredWidth: 150 + id: functionRect + + function hide() + { + parent.visible = false + functionRect.visible = false + functionComboBox.visible = false + } + + function show() + { + parent.visible = true + functionRect.visible = true + functionComboBox.visible = true + } + + Label { + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right text: qsTr("Function") } - ComboBox { - id: functionComboBox - Layout.preferredWidth: 350 - currentIndex: -1 - textRole: "text" - editable: false - model: ListModel { - id: functionsModel - } - onCurrentIndexChanged: { - loadParameters(); - } + } + + ComboBox { + id: functionComboBox + Layout.preferredWidth: 350 + currentIndex: -1 + textRole: "text" + editable: false + model: ListModel { + id: functionsModel + } + onCurrentIndexChanged: { + loadParameters(); } } + } - CommonSeparator + StructView + { + id: paramScroll + members: paramsModel; + accounts: senderComboBox.model + context: "parameter" + Layout.fillWidth: true + function updateView() { - Layout.fillWidth: true + paramScroll.visible = paramsModel.length > 0 + paramScroll.Layout.preferredHeight = paramsModel.length < 6 ? paramsModel.length * 30 : 205 + if (paramsModel.length === 0) + { + paramScroll.height = 0 + } } + } - RowLayout + RowLayout + { + Rectangle { - id: rowValue - Layout.fillWidth: true - height: 150 - DefaultLabel { - Layout.preferredWidth: 75 - text: qsTr("Value") - } - Ether { - id: valueField - edit: true - displayFormattedValue: true + Layout.preferredWidth: 150 + Label { + id: amountLabel + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + text: qsTr("Amount") } } - CommonSeparator + Ether { + Layout.preferredWidth: 350 + id: valueField + edit: true + displayFormattedValue: false + displayUnitSelection: true + } + } + + Rectangle + { + Layout.preferredHeight: 30 + Layout.fillWidth: true + color: "transparent" + Rectangle + { + color: "#cccccc" + height: 1 + width: parent.width + anchors.verticalCenter: parent.verticalCenter + } + } + + Rectangle + { + height: 20 + color: "transparent" + Layout.preferredWidth: 500 + Rectangle { - Layout.fillWidth: true + + anchors.horizontalCenter: parent.horizontalCenter + Label { + text: qsTr("Transaction fees") + anchors.horizontalCenter: parent.horizontalCenter + } } - RowLayout + } + + RowLayout + { + Layout.preferredHeight: 45 + Rectangle { - id: rowGas - Layout.fillWidth: true - height: 150 - DefaultLabel { - Layout.preferredWidth: 75 + Layout.preferredWidth: 150 + Label { + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right text: qsTr("Gas") } + } + Row + { + Layout.preferredWidth: 350 DefaultTextField { property variant gasValue @@ -435,6 +575,55 @@ Dialog { implicitWidth: 200 enabled: !gasAutoCheck.checked id: gasValueEdit; + + Label + { + id: estimatedGas + anchors.top: parent.bottom + text: "" + Connections + { + target: functionComboBox + onCurrentIndexChanged: + { + estimatedGas.displayGas(contractFromToken(recipientsAccount.currentValue()), functionComboBox.currentText) + } + } + + function displayGas(contractName, functionName) + { + var gasCost = codeModel.gasCostBy(contractName, functionName); + if (gasCost && gasCost.length > 0) + { + var gas = codeModel.txGas + codeModel.callStipend + parseInt(gasCost[0].gas) + estimatedGas.text = qsTr("Estimated cost: ") + gasCost[0].gas + " gas" + } + } + + function updateView() + { + if (rbbuttonList.current.objectName === "trTypeExecute") + estimatedGas.displayGas(contractFromToken(recipientsAccount.currentValue()), functionComboBox.currentText) + else if (rbbuttonList.current.objectName === "trTypeCreate") + { + var contractName = contractCreationComboBox.currentValue() + estimatedGas.displayGas(contractName, contractName) + } + else if (rbbuttonList.current.objectName === "trTypeSend") + { + var gas = codeModel.txGas + codeModel.callStipend + estimatedGas.text = qsTr("Estimated cost: ") + gas + " gas" + } + } + + Connections + { + target: rbbuttonList + onCurrentChanged: { + estimatedGas.updateView() + } + } + } } CheckBox @@ -444,101 +633,92 @@ Dialog { text: qsTr("Auto"); } } + } - CommonSeparator - { - Layout.fillWidth: true - } - - RowLayout + RowLayout + { + Layout.preferredWidth: 500 + Layout.preferredHeight: 45 + Rectangle { - id: rowGasPrice - Layout.fillWidth: true - height: 150 - DefaultLabel { - Layout.preferredWidth: 75 + Layout.preferredWidth: 150 + Label { + id: gasPriceLabel + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right text: qsTr("Gas Price") - } - Ether { - id: gasPriceField - edit: true - displayFormattedValue: true - } - } - - CommonSeparator - { - Layout.fillWidth: true - } - DefaultLabel { - id: paramLabel - text: qsTr("Parameters:") - Layout.preferredWidth: 75 - } - - ScrollView - { - id: paramScroll - anchors.top: paramLabel.bottom - anchors.topMargin: 10 - Layout.fillWidth: true - Layout.fillHeight: true - StructView - { - id: typeLoader - Layout.preferredWidth: 150 - members: paramsModel; - accounts: senderComboBox.model - context: "parameter" + Label { + id: gasPriceMarket + anchors.top: gasPriceLabel.bottom + Component.onCompleted: + { + NetworkDeployment.gasPrice(function(result) + { + gasPriceMarket.text = qsTr("Current market: ") + " " + result + " Wei"; + }, function (){}); + } + } } } - CommonSeparator - { - Layout.fillWidth: true - visible: paramsModel.length > 0 + Ether { + Layout.preferredWidth: 350 + id: gasPriceField + edit: true + displayFormattedValue: false + displayUnitSelection: true } } - } - RowLayout - { - anchors.bottom: parent.bottom - anchors.right: parent.right; - Button { + RowLayout + { - text: qsTr("OK"); - onClicked: { - var invalid = InputValidator.validate(paramsModel, paramValues); - if (invalid.length === 0) - { - close(); - accepted(); + Layout.preferredWidth: 500 + Row + { + width: parent.width + anchors.right: parent.right + Button { + id: updateBtn + text: qsTr("Cancel"); + onClicked: close(); } - else - { - errorDialog.text = qsTr("Some parameters are invalid:\n"); - for (var k in invalid) - errorDialog.text += invalid[k].message + "\n"; - errorDialog.open(); + + Button { + text: qsTr("Update"); + onClicked: { + var invalid = InputValidator.validate(paramsModel, paramValues); + if (invalid.length === 0) + { + close(); + accepted(); + } + else + { + errorDialog.text = qsTr("Some parameters are invalid:\n"); + for (var k in invalid) + errorDialog.text += invalid[k].message + "\n"; + errorDialog.open(); + } + } } } - } - Button { - text: qsTr("Cancel"); - onClicked: close(); + MessageDialog { + id: errorDialog + standardButtons: StandardButton.Ok + icon: StandardIcon.Critical + } } - MessageDialog { - id: errorDialog - standardButtons: StandardButton.Ok - icon: StandardIcon.Critical + RowLayout + { + Layout.preferredHeight: 30 + anchors.bottom: parent.bottom } } } } } - diff --git a/mix/qml/WebPreview.qml b/mix/qml/WebPreview.qml index e4d0b61a5..5d0f208af 100644 --- a/mix/qml/WebPreview.qml +++ b/mix/qml/WebPreview.qml @@ -89,11 +89,6 @@ Item { } } - Connections { - target: clientModel - onRunComplete: reload(); - } - Connections { target: codeModel onContractInterfaceChanged: reload(); diff --git a/mix/qml/img/edittransaction.png b/mix/qml/img/edittransaction.png new file mode 100644 index 000000000..fac8954ef Binary files /dev/null and b/mix/qml/img/edittransaction.png differ diff --git a/mix/qml/img/edittransaction2.png b/mix/qml/img/edittransaction2.png new file mode 100644 index 000000000..55ffe2ad8 Binary files /dev/null and b/mix/qml/img/edittransaction2.png differ diff --git a/mix/qml/img/edittransaction2@2x.png b/mix/qml/img/edittransaction2@2x.png new file mode 100644 index 000000000..e925679a9 Binary files /dev/null and b/mix/qml/img/edittransaction2@2x.png differ diff --git a/mix/qml/img/edittransaction@2x.png b/mix/qml/img/edittransaction@2x.png new file mode 100644 index 000000000..9f440fe14 Binary files /dev/null and b/mix/qml/img/edittransaction@2x.png differ diff --git a/mix/qml/img/newblock.png b/mix/qml/img/newblock.png new file mode 100644 index 000000000..04694412c Binary files /dev/null and b/mix/qml/img/newblock.png differ diff --git a/mix/qml/img/newblock@2x.png b/mix/qml/img/newblock@2x.png new file mode 100644 index 000000000..42ea02f5f Binary files /dev/null and b/mix/qml/img/newblock@2x.png differ diff --git a/mix/qml/js/NetworkDeployment.js b/mix/qml/js/NetworkDeployment.js index 8a833e144..94d83460f 100644 --- a/mix/qml/js/NetworkDeployment.js +++ b/mix/qml/js/NetworkDeployment.js @@ -201,7 +201,7 @@ function executeTrNextStep(trIndex, state, ctrAddresses, callBack) callBack(); } -function gasPrice(callBack) +function gasPrice(callBack, error) { var requests = [{ jsonrpc: "2.0", @@ -210,7 +210,9 @@ function gasPrice(callBack) id: jsonRpcRequestId }]; rpcCall(requests, function (httpCall, response){ - callBack(JSON.parse(response)[0].result); + callBack(JSON.parse(response)[0].result) + }, function(message){ + error(message) }); } diff --git a/mix/qml/js/TransactionHelper.js b/mix/qml/js/TransactionHelper.js index f8bad03ed..ea91a40d7 100644 --- a/mix/qml/js/TransactionHelper.js +++ b/mix/qml/js/TransactionHelper.js @@ -17,7 +17,7 @@ function defaultTransaction() }; } -function rpcCall(requests, callBack) +function rpcCall(requests, callBack, error) { var jsonRpcUrl = "http://localhost:8545"; var rpcRequest = JSON.stringify(requests); @@ -33,7 +33,7 @@ function rpcCall(requests, callBack) { var errorText = qsTr("Unable to initiate request to the live network. Please verify your ethereum node is up.") + qsTr(" Error status: ") + httpRequest.status; console.log(errorText); - deploymentError(errorText); + error(errorText); } else { diff --git a/neth/CMakeLists.txt b/neth/CMakeLists.txt index c500b83df..48b6408dc 100644 --- a/neth/CMakeLists.txt +++ b/neth/CMakeLists.txt @@ -4,7 +4,7 @@ aux_source_directory(. SRC_LIST) include_directories(BEFORE ..) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) -include_directories(${LEVELDB_INCLUDE_DIRS}) +include_directories(${DB_INCLUDE_DIRS}) include_directories(${Boost_INCLUDE_DIRS}) set(EXECUTABLE neth) @@ -13,8 +13,6 @@ add_executable(${EXECUTABLE} ${SRC_LIST}) add_dependencies(${EXECUTABLE} BuildInfo.h) -target_link_libraries(${EXECUTABLE} ${LEVELDB_LIBRARIES}) - if (JSONRPC) target_link_libraries(${EXECUTABLE} web3jsonrpc) endif() diff --git a/rlp/CMakeLists.txt b/rlp/CMakeLists.txt index 92d0c7978..9946cd4af 100644 --- a/rlp/CMakeLists.txt +++ b/rlp/CMakeLists.txt @@ -4,13 +4,14 @@ set(CMAKE_AUTOMOC OFF) aux_source_directory(. SRC_LIST) include_directories(BEFORE ..) -include_directories(${LEVELDB_INCLUDE_DIRS}) +include_directories(${DB_INCLUDE_DIRS}) set(EXECUTABLE rlp) add_executable(${EXECUTABLE} ${SRC_LIST}) target_link_libraries(${EXECUTABLE} devcrypto) +target_link_libraries(${EXECUTABLE} ${DB_LIBRARIES}) if (APPLE) install(TARGETS ${EXECUTABLE} DESTINATION bin) diff --git a/sanitizer-blacklist.txt b/sanitizer-blacklist.txt new file mode 100644 index 000000000..0faf73cf4 --- /dev/null +++ b/sanitizer-blacklist.txt @@ -0,0 +1,8 @@ +# Ignore standard library headers. +src:*/include/c\+\+/* + +# Ignore boost libraries headers. +src:*/include/boost/* + +# Ignore Crypto++ library. We plan to remove it in the future. It exploits interger overflow and uses memcpy incorrectly. +src:*/include/cryptopp/* diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index ec2a90033..c95f34f62 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -273,6 +273,11 @@ void CommandLineInterface::handleGasEstimation(string const& _contract) GasEstimator::GasConsumption gas = GasEstimator::functionalEstimation(*items, sig); cout << " " << sig << ":\t" << gas << endl; } + if (contract.getFallbackFunction()) + { + GasEstimator::GasConsumption gas = GasEstimator::functionalEstimation(*items, "INVALID"); + cout << " fallback:\t" << gas << endl; + } cout << "internal:" << endl; for (auto const& it: contract.getDefinedFunctions()) { diff --git a/solc/jsonCompiler.cpp b/solc/jsonCompiler.cpp index 7bde3e47c..340713b1d 100644 --- a/solc/jsonCompiler.cpp +++ b/solc/jsonCompiler.cpp @@ -91,6 +91,8 @@ Json::Value estimateGas(CompilerStack const& _compiler, string const& _contract) string sig = it.second->externalSignature(); externalFunctions[sig] = gasToJson(GasEstimator::functionalEstimation(*items, sig)); } + if (contract.getFallbackFunction()) + externalFunctions[""] = gasToJson(GasEstimator::functionalEstimation(*items, "INVALID")); gasEstimates["external"] = externalFunctions; Json::Value internalFunctions(Json::objectValue); for (auto const& it: contract.getDefinedFunctions()) diff --git a/test/TestHelper.cpp b/test/TestHelper.cpp index 6c1db8eea..698f35122 100644 --- a/test/TestHelper.cpp +++ b/test/TestHelper.cpp @@ -178,7 +178,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state, stateOptio { stateOptions.m_bHasBalance = true; if (bigint(o["balance"].get_str()) >= c_max256plus1) - TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'balance' is equal or greater than 2**256") ); + BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'balance' is equal or greater than 2**256") ); balance = toInt(o["balance"]); } @@ -186,7 +186,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state, stateOptio { stateOptions.m_bHasNonce = true; if (bigint(o["nonce"].get_str()) >= c_max256plus1) - TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'nonce' is equal or greater than 2**256") ); + BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("State 'nonce' is equal or greater than 2**256") ); nonce = toInt(o["nonce"]); } @@ -230,7 +230,7 @@ void ImportTest::importState(json_spirit::mObject& _o, State& _state) { //check that every parameter was declared in state object if (!stateOptionMap.second.isAllSet()) - TBOOST_THROW_EXCEPTION(MissingFields() << errinfo_comment("Import State: Missing state fields!")); + BOOST_THROW_EXCEPTION(MissingFields() << errinfo_comment("Import State: Missing state fields!")); } } @@ -246,13 +246,13 @@ void ImportTest::importTransaction(json_spirit::mObject& _o) assert(_o.count("data") > 0); if (bigint(_o["nonce"].get_str()) >= c_max256plus1) - TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'nonce' is equal or greater than 2**256") ); + BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'nonce' is equal or greater than 2**256") ); if (bigint(_o["gasPrice"].get_str()) >= c_max256plus1) - TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasPrice' is equal or greater than 2**256") ); + BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasPrice' is equal or greater than 2**256") ); if (bigint(_o["gasLimit"].get_str()) >= c_max256plus1) - TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasLimit' is equal or greater than 2**256") ); + BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'gasLimit' is equal or greater than 2**256") ); if (bigint(_o["value"].get_str()) >= c_max256plus1) - TBOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'value' is equal or greater than 2**256") ); + BOOST_THROW_EXCEPTION(ValueTooLarge() << errinfo_comment("Transaction 'value' is equal or greater than 2**256") ); m_transaction = _o["to"].get_str().empty() ? Transaction(toInt(_o["value"]), toInt(_o["gasPrice"]), toInt(_o["gasLimit"]), importData(_o), toInt(_o["nonce"]), Secret(_o["secretKey"].get_str())) : @@ -349,9 +349,9 @@ void ImportTest::exportTest(bytes const& _output, State const& _statePost) { 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); + {TBOOST_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); + TBOOST_WARN_MESSAGE((m_TestObject["out"].get_str() == m_TestObject["expectOut"].get_str()), warning); m_TestObject.erase(m_TestObject.find("expectOut")); } @@ -533,24 +533,25 @@ void checkOutput(bytes const& _output, json_spirit::mObject& _o) void checkStorage(map _expectedStore, map _resultStore, Address _expectedAddr) { + _expectedAddr = _expectedAddr; //unsed parametr when macro for (auto&& expectedStorePair : _expectedStore) { auto& expectedStoreKey = expectedStorePair.first; auto resultStoreIt = _resultStore.find(expectedStoreKey); if (resultStoreIt == _resultStore.end()) - BOOST_ERROR(_expectedAddr << ": missing store key " << expectedStoreKey); + {TBOOST_ERROR(_expectedAddr << ": missing store key " << expectedStoreKey);} else { auto& expectedStoreValue = expectedStorePair.second; auto& resultStoreValue = resultStoreIt->second; - BOOST_CHECK_MESSAGE(expectedStoreValue == resultStoreValue, _expectedAddr << ": store[" << expectedStoreKey << "] = " << resultStoreValue << ", expected " << expectedStoreValue); + TBOOST_CHECK_MESSAGE((expectedStoreValue == resultStoreValue), _expectedAddr << ": store[" << expectedStoreKey << "] = " << resultStoreValue << ", expected " << expectedStoreValue); } } - BOOST_CHECK_EQUAL(_resultStore.size(), _expectedStore.size()); + TBOOST_CHECK_EQUAL(_resultStore.size(), _expectedStore.size()); for (auto&& resultStorePair: _resultStore) { if (!_expectedStore.count(resultStorePair.first)) - BOOST_ERROR(_expectedAddr << ": unexpected store key " << resultStorePair.first); + TBOOST_ERROR(_expectedAddr << ": unexpected store key " << resultStorePair.first); } } @@ -568,14 +569,14 @@ void checkLog(LogEntries _resultLogs, LogEntries _expectedLogs) void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _expectedCallCreates) { - BOOST_REQUIRE_EQUAL(_resultCallCreates.size(), _expectedCallCreates.size()); + TBOOST_REQUIRE_EQUAL(_resultCallCreates.size(), _expectedCallCreates.size()); for (size_t i = 0; i < _resultCallCreates.size(); ++i) { - BOOST_CHECK(_resultCallCreates[i].data() == _expectedCallCreates[i].data()); - BOOST_CHECK(_resultCallCreates[i].receiveAddress() == _expectedCallCreates[i].receiveAddress()); - BOOST_CHECK(_resultCallCreates[i].gas() == _expectedCallCreates[i].gas()); - BOOST_CHECK(_resultCallCreates[i].value() == _expectedCallCreates[i].value()); + TBOOST_CHECK((_resultCallCreates[i].data() == _expectedCallCreates[i].data())); + TBOOST_CHECK((_resultCallCreates[i].receiveAddress() == _expectedCallCreates[i].receiveAddress())); + TBOOST_CHECK((_resultCallCreates[i].gas() == _expectedCallCreates[i].gas())); + TBOOST_CHECK((_resultCallCreates[i].value() == _expectedCallCreates[i].value())); } } @@ -598,7 +599,7 @@ void userDefinedTest(std::function doTests) cnote << "Testing user defined test: " << filename; json_spirit::mValue v; string s = contentsString(filename); - BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + filename + " is empty. "); + TBOOST_REQUIRE_MESSAGE((s.length() > 0), "Contents of " + filename + " is empty. "); json_spirit::read_string(s, v); json_spirit::mObject oSingleTest; @@ -616,11 +617,11 @@ void userDefinedTest(std::function doTests) } catch (Exception const& _e) { - BOOST_ERROR("Failed Test with Exception: " << diagnostic_information(_e)); + TBOOST_ERROR("Failed Test with Exception: " << diagnostic_information(_e)); } catch (std::exception const& _e) { - BOOST_ERROR("Failed Test with Exception: " << _e.what()); + TBOOST_ERROR("Failed Test with Exception: " << _e.what()); } } @@ -640,18 +641,18 @@ void executeTests(const string& _name, const string& _testPathAppendix, const bo json_spirit::mValue v; boost::filesystem::path p(__FILE__); string s = asString(dev::contents(_pathToFiller.string() + "/" + _name + "Filler.json")); - BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + _pathToFiller.string() + "/" + _name + "Filler.json is empty."); + TBOOST_REQUIRE_MESSAGE((s.length() > 0), "Contents of " + _pathToFiller.string() + "/" + _name + "Filler.json is empty."); json_spirit::read_string(s, v); doTests(v, true); writeFile(testPath + "/" + _name + ".json", asBytes(json_spirit::write_string(v, true))); } catch (Exception const& _e) { - BOOST_ERROR("Failed filling test with Exception: " << diagnostic_information(_e)); + TBOOST_ERROR("Failed filling test with Exception: " << diagnostic_information(_e)); } catch (std::exception const& _e) { - BOOST_ERROR("Failed filling test with Exception: " << _e.what()); + TBOOST_ERROR("Failed filling test with Exception: " << _e.what()); } } @@ -660,18 +661,18 @@ void executeTests(const string& _name, const string& _testPathAppendix, const bo std::cout << "TEST " << _name << ":\n"; json_spirit::mValue v; string s = asString(dev::contents(testPath + "/" + _name + ".json")); - BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + testPath + "/" + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"); + TBOOST_REQUIRE_MESSAGE((s.length() > 0), "Contents of " + testPath + "/" + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?"); json_spirit::read_string(s, v); Listener::notifySuiteStarted(_name); doTests(v, false); } catch (Exception const& _e) { - BOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e)); + TBOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e)); } catch (std::exception const& _e) { - BOOST_ERROR("Failed test with Exception: " << _e.what()); + TBOOST_ERROR("Failed test with Exception: " << _e.what()); } } diff --git a/test/TestHelper.h b/test/TestHelper.h index c21429ef4..1c1dfb5f0 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -32,21 +32,21 @@ #include #ifdef NOBOOST - #define TBOOST_THROW_EXCEPTION(arg) throw dev::Exception(); #define TBOOST_REQUIRE(arg) if(arg == false) throw dev::Exception(); #define TBOOST_REQUIRE_EQUAL(arg1, arg2) if(arg1 != arg2) throw dev::Exception(); #define TBOOST_CHECK_EQUAL(arg1, arg2) if(arg1 != arg2) throw dev::Exception(); #define TBOOST_CHECK(arg) if(arg == false) throw dev::Exception(); + #define TBOOST_REQUIRE_MESSAGE(arg1, arg2) if(arg1 == false) throw dev::Exception(); #define TBOOST_CHECK_MESSAGE(arg1, arg2) if(arg1 == false) throw dev::Exception(); #define TBOOST_WARN_MESSAGE(arg1, arg2) throw dev::Exception(); #define TBOOST_ERROR(arg) throw dev::Exception(); #else - #define TBOOST_THROW_EXCEPTION(arg) BOOST_THROW_EXCEPTION(arg) #define TBOOST_REQUIRE(arg) BOOST_REQUIRE(arg) #define TBOOST_REQUIRE_EQUAL(arg1, arg2) BOOST_REQUIRE_EQUAL(arg1, arg2) #define TBOOST_CHECK(arg) BOOST_CHECK(arg) #define TBOOST_CHECK_EQUAL(arg1, arg2) BOOST_CHECK_EQUAL(arg1, arg2) #define TBOOST_CHECK_MESSAGE(arg1, arg2) BOOST_CHECK_MESSAGE(arg1, arg2) + #define TBOOST_REQUIRE_MESSAGE(arg1, arg2) BOOST_REQUIRE_MESSAGE(arg1, arg2) #define TBOOST_WARN_MESSAGE(arg1, arg2) BOOST_WARN_MESSAGE(arg1, arg2) #define TBOOST_ERROR(arg) BOOST_ERROR(arg) #endif @@ -224,7 +224,7 @@ public: bool bigData = false; bool wallet = false; bool nonetwork = false; - bool nodag = false; + bool nodag = true; /// @} /// Get reference to options diff --git a/test/fuzzTesting/createRandomTest.cpp b/test/fuzzTesting/createRandomTest.cpp index e21f22eea..b4a00440e 100644 --- a/test/fuzzTesting/createRandomTest.cpp +++ b/test/fuzzTesting/createRandomTest.cpp @@ -36,8 +36,8 @@ extern std::string const c_testExampleVMTest; extern std::string const c_testExampleBlockchainTest; //Main Test functinos -void fillRandomTest(std::function doTests, std::string const& testString); -int checkRandomTest(std::function doTests, json_spirit::mValue& value); +void fillRandomTest(std::function _doTests, std::string const& _testString, bool _debug = false); +int checkRandomTest(std::function _doTests, json_spirit::mValue& _value, bool _debug = false); //Helper Functions std::vector getTypes(); @@ -46,8 +46,12 @@ void parseTestWithTypes(std::string& test); int main(int argc, char *argv[]) { std::string testSuite; + std::string testFillString; json_spirit::mValue testmValue; bool checktest = false; + bool filldebug = false; + bool debug = false; + bool filltest = false; for (auto i = 0; i < argc; ++i) { auto arg = std::string{argv[i]}; @@ -62,7 +66,7 @@ int main(int argc, char *argv[]) testSuite = ""; } else - if (arg == "-checktest" && i + 1 < argc) + if ((arg == "-checktest" || arg == "-filltest") && i + 1 < argc) { std::string s; for (int j = i+1; j < argc; ++j) @@ -72,9 +76,23 @@ int main(int argc, char *argv[]) std::cout << "Error! Content of argument is empty! (Usage -checktest textstream) \n"; return 1; } - read_string(s, testmValue); - checktest = true; + if (arg == "-filltest") + { + testFillString = s; + filltest = true; + } + else + { + read_string(s, testmValue); + checktest = true; + } } + else + if (arg == "--debug") + debug = true; + else + if (arg == "--filldebug") + filldebug = true; } if (testSuite == "") @@ -83,45 +101,50 @@ int main(int argc, char *argv[]) return 1; } else - if (testSuite == "BlockChainTests") { if (checktest) - return checkRandomTest(dev::test::doBlockchainTests, testmValue); - else - fillRandomTest(dev::test::doBlockchainTests, c_testExampleBlockchainTest); - } - else - if (testSuite == "TransactionTests") - { - if (checktest) - return checkRandomTest(dev::test::doTransactionTests, testmValue); + std::cout << "Testing: " << testSuite.substr(0, testSuite.length() - 1) << std::endl; + + if (testSuite == "BlockChainTests") + { + if (checktest) + return checkRandomTest(dev::test::doBlockchainTests, testmValue, debug); + else + fillRandomTest(dev::test::doBlockchainTests, (filltest) ? testFillString : c_testExampleBlockchainTest, filldebug); + } else - fillRandomTest(dev::test::doTransactionTests, c_testExampleTransactionTest); - } - else - if (testSuite == "StateTests") - { - if (checktest) - return checkRandomTest(dev::test::doStateTests, testmValue); + if (testSuite == "TransactionTests") + { + if (checktest) + return checkRandomTest(dev::test::doTransactionTests, testmValue, debug); + else + fillRandomTest(dev::test::doTransactionTests, (filltest) ? testFillString : c_testExampleTransactionTest, filldebug); + } else - fillRandomTest(dev::test::doStateTests, c_testExampleStateTest); - } - else - if (testSuite == "VMTests") - { - if (checktest) + if (testSuite == "StateTests") { - dev::eth::VMFactory::setKind(dev::eth::VMKind::JIT); - return checkRandomTest(dev::test::doVMTests, testmValue); + if (checktest) + return checkRandomTest(dev::test::doStateTests, testmValue, debug); + else + fillRandomTest(dev::test::doStateTests, (filltest) ? testFillString : c_testExampleStateTest, filldebug); } else - fillRandomTest(dev::test::doVMTests, c_testExampleVMTest); + if (testSuite == "VMTests") + { + if (checktest) + { + dev::eth::VMFactory::setKind(dev::eth::VMKind::JIT); + return checkRandomTest(dev::test::doVMTests, testmValue, debug); + } + else + fillRandomTest(dev::test::doVMTests, (filltest) ? testFillString : c_testExampleVMTest, filldebug); + } } return 0; } -int checkRandomTest(std::function doTests, json_spirit::mValue& value) +int checkRandomTest(std::function _doTests, json_spirit::mValue& _value, bool _debug) { bool ret = 0; try @@ -129,14 +152,20 @@ int checkRandomTest(std::function doTests, jso //redirect all output to the stream std::ostringstream strCout; std::streambuf* oldCoutStreamBuf = std::cout.rdbuf(); - std::cout.rdbuf( strCout.rdbuf() ); - std::cerr.rdbuf( strCout.rdbuf() ); + if (!_debug) + { + std::cout.rdbuf( strCout.rdbuf() ); + std::cerr.rdbuf( strCout.rdbuf() ); + } - doTests(value, false); + _doTests(_value, false); //restroe output - std::cout.rdbuf(oldCoutStreamBuf); - std::cerr.rdbuf(oldCoutStreamBuf); + if (!_debug) + { + std::cout.rdbuf(oldCoutStreamBuf); + std::cerr.rdbuf(oldCoutStreamBuf); + } } catch (dev::Exception const& _e) { @@ -151,21 +180,24 @@ int checkRandomTest(std::function doTests, jso return ret; } -void fillRandomTest(std::function doTests, std::string const& testString) +void fillRandomTest(std::function _doTests, std::string const& _testString, bool _debug) { //redirect all output to the stream std::ostringstream strCout; std::streambuf* oldCoutStreamBuf = std::cout.rdbuf(); - std::cout.rdbuf( strCout.rdbuf() ); - std::cerr.rdbuf( strCout.rdbuf() ); + if (!_debug) + { + std::cout.rdbuf( strCout.rdbuf() ); + std::cerr.rdbuf( strCout.rdbuf() ); + } json_spirit::mValue v; try { - std::string newTest = testString; + std::string newTest = _testString; parseTestWithTypes(newTest); json_spirit::read_string(newTest, v); - doTests(v, true); + _doTests(v, true); } catch(...) { @@ -173,8 +205,11 @@ void fillRandomTest(std::function doTests, std } //restroe output - std::cout.rdbuf(oldCoutStreamBuf); - std::cerr.rdbuf(oldCoutStreamBuf); + if (!_debug) + { + std::cout.rdbuf(oldCoutStreamBuf); + std::cerr.rdbuf(oldCoutStreamBuf); + } std::cout << json_spirit::write_string(v, true); } diff --git a/test/libdevcrypto/trie.cpp b/test/libdevcrypto/trie.cpp index daa3cc181..720001f9c 100644 --- a/test/libdevcrypto/trie.cpp +++ b/test/libdevcrypto/trie.cpp @@ -585,7 +585,7 @@ template void perfTestTrie(char const* _name) d.init(); cnote << "TriePerf " << _name << p; std::vector keys(1000); - boost::timer t; + Timer t; size_t ki = 0; for (size_t i = 0; i < p; ++i) { diff --git a/test/libethcore/keymanager.cpp b/test/libethcore/keymanager.cpp new file mode 100644 index 000000000..44ee9ae51 --- /dev/null +++ b/test/libethcore/keymanager.cpp @@ -0,0 +1,124 @@ +/* + 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 keymanager.cpp + * @author Christoph Jentzsch + * @date 2015 + * Keymanager test functions. + */ + + +#include +#include +#include +#include + +using namespace std; +using namespace dev; +using namespace dev::eth; + +BOOST_AUTO_TEST_SUITE(KeyManagerTests) + +BOOST_AUTO_TEST_CASE(KeyInfoDefaultConstructor) +{ + cnote << "KeyInfoDefaultConstructor"; + KeyInfo kiDefault; + BOOST_CHECK_EQUAL(kiDefault.accountName, ""); + BOOST_CHECK(kiDefault.passHash == h256()); +} + +BOOST_AUTO_TEST_CASE(KeyInfoConstructor) +{ + cnote << "KeyInfoConstructor"; + h256 passHash("0x2a"); + string accountName = "myAccount"; + KeyInfo ki(passHash, accountName); + BOOST_CHECK_EQUAL(ki.accountName, "myAccount"); + BOOST_CHECK(ki.passHash == h256("0x2a")); +} + +BOOST_AUTO_TEST_CASE(KeyManagerConstructor) +{ + cnote << "KeyManagerConstructor"; + KeyManager km; + BOOST_CHECK_EQUAL(km.keysFile(), km.defaultPath()); + BOOST_CHECK_EQUAL(km.defaultPath(), getDataDir("ethereum") + "/keys.info"); + BOOST_CHECK(km.store().keys() == SecretStore().keys()); + for (auto a: km.accounts()) + km.kill(a); +} + +BOOST_AUTO_TEST_CASE(KeyManagerKeysFile) +{ + cnote << "KeyManagerKeysFile"; + KeyManager km; + string password = "hardPassword"; + BOOST_CHECK(!km.load(password)); + + // set to valid path + TransientDirectory tmpDir; + km.setKeysFile(tmpDir.path()); + BOOST_CHECK(!km.exists()); + BOOST_CHECK_THROW(km.create(password), FileError); + km.setKeysFile(tmpDir.path() + "/notExistingDir/keysFile.json"); + BOOST_CHECK_NO_THROW(km.create(password)); + BOOST_CHECK(km.exists()); + km.setKeysFile(tmpDir.path() + "keysFile.json"); + BOOST_CHECK_NO_THROW(km.create(password)); + km.save(password); + BOOST_CHECK(km.load(password)); + + for (auto a: km.accounts()) + km.kill(a); +} + +BOOST_AUTO_TEST_CASE(KeyManagerHints) +{ + cnote << "KeyManagerHints"; + KeyManager km; + string password = "hardPassword"; + + // set to valid path + TransientDirectory tmpDir; + km.setKeysFile(tmpDir.path() + "keysFile.json"); + km.create(password); + km.save(password); + + BOOST_CHECK(!km.haveHint(password + "2")); + km.notePassword(password); + BOOST_CHECK(km.haveHint(password)); + + for (auto a: km.accounts()) + km.kill(a); +} + +BOOST_AUTO_TEST_CASE(KeyManagerAccounts) +{ + KeyManager km; + string password = "hardPassword"; + + TransientDirectory tmpDir; + km.setKeysFile(tmpDir.path()+ "keysFile.json"); + + BOOST_CHECK_NO_THROW(km.create(password)); + BOOST_CHECK(km.accounts().empty()); + BOOST_CHECK(km.load(password)); + + for (auto a: km.accounts()) + km.kill(a); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libethereum/BlockTestsFiller/bcGasPricerTestFiller.json b/test/libethereum/BlockchainTestsFiller/bcGasPricerTestFiller.json similarity index 100% rename from test/libethereum/BlockTestsFiller/bcGasPricerTestFiller.json rename to test/libethereum/BlockchainTestsFiller/bcGasPricerTestFiller.json diff --git a/test/libethereum/BlockTestsFiller/bcInvalidHeaderTestFiller.json b/test/libethereum/BlockchainTestsFiller/bcInvalidHeaderTestFiller.json similarity index 100% rename from test/libethereum/BlockTestsFiller/bcInvalidHeaderTestFiller.json rename to test/libethereum/BlockchainTestsFiller/bcInvalidHeaderTestFiller.json diff --git a/test/libethereum/BlockTestsFiller/bcRPC_API_TestFiller.json b/test/libethereum/BlockchainTestsFiller/bcRPC_API_TestFiller.json similarity index 100% rename from test/libethereum/BlockTestsFiller/bcRPC_API_TestFiller.json rename to test/libethereum/BlockchainTestsFiller/bcRPC_API_TestFiller.json diff --git a/test/libethereum/BlockTestsFiller/bcTotalDifficultyTestFiller.json b/test/libethereum/BlockchainTestsFiller/bcTotalDifficultyTestFiller.json similarity index 100% rename from test/libethereum/BlockTestsFiller/bcTotalDifficultyTestFiller.json rename to test/libethereum/BlockchainTestsFiller/bcTotalDifficultyTestFiller.json diff --git a/test/libethereum/BlockTestsFiller/bcUncleHeaderValiditiyFiller.json b/test/libethereum/BlockchainTestsFiller/bcUncleHeaderValiditiyFiller.json similarity index 100% rename from test/libethereum/BlockTestsFiller/bcUncleHeaderValiditiyFiller.json rename to test/libethereum/BlockchainTestsFiller/bcUncleHeaderValiditiyFiller.json diff --git a/test/libethereum/BlockTestsFiller/bcUncleTestFiller.json b/test/libethereum/BlockchainTestsFiller/bcUncleTestFiller.json similarity index 100% rename from test/libethereum/BlockTestsFiller/bcUncleTestFiller.json rename to test/libethereum/BlockchainTestsFiller/bcUncleTestFiller.json diff --git a/test/libethereum/BlockTestsFiller/bcValidBlockTestFiller.json b/test/libethereum/BlockchainTestsFiller/bcValidBlockTestFiller.json similarity index 100% rename from test/libethereum/BlockTestsFiller/bcValidBlockTestFiller.json rename to test/libethereum/BlockchainTestsFiller/bcValidBlockTestFiller.json diff --git a/test/libethereum/BlockTestsFiller/bcWalletTestFiller.json b/test/libethereum/BlockchainTestsFiller/bcWalletTestFiller.json similarity index 100% rename from test/libethereum/BlockTestsFiller/bcWalletTestFiller.json rename to test/libethereum/BlockchainTestsFiller/bcWalletTestFiller.json diff --git a/test/libethereum/StateTestsFiller/stSystemOperationsTestFiller.json b/test/libethereum/StateTestsFiller/stSystemOperationsTestFiller.json index 16ab3b002..3c8d8e08f 100644 --- a/test/libethereum/StateTestsFiller/stSystemOperationsTestFiller.json +++ b/test/libethereum/StateTestsFiller/stSystemOperationsTestFiller.json @@ -1638,6 +1638,46 @@ } }, + "suicideCoinbase": { + "env" : { + "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", + "currentNumber" : "0", + "currentGasLimit" : "10000000", + "currentDifficulty" : "256", + "currentTimestamp" : 1, + "currentCoinbase" : "095e7baea6a6c7c4c2dfeb977efac326af552d87" + }, + "expect" : { + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1999999999999979496", + "nonce" : "1" + } + }, + "pre" : { + "095e7baea6a6c7c4c2dfeb977efac326af552d87" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "{ (SUICIDE 0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b) }", + "storage": {} + }, + "a94f5374fce5edbc8e2a8697c15331677e6ebf0b" : { + "balance" : "1000000000000000000", + "nonce" : "0", + "code" : "", + "storage": {} + } + }, + "transaction" : { + "nonce" : "0", + "gasPrice" : "1", + "gasLimit" : "1000000", + "to" : "095e7baea6a6c7c4c2dfeb977efac326af552d87", + "value" : "100000", + "secretKey" : "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8", + "data" : "" + } + }, + "suicideCaller": { "env" : { "previousHash" : "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6", diff --git a/test/libethereum/blockchain.cpp b/test/libethereum/blockchain.cpp index 4621708bd..0314de78b 100644 --- a/test/libethereum/blockchain.cpp +++ b/test/libethereum/blockchain.cpp @@ -788,58 +788,58 @@ BOOST_AUTO_TEST_SUITE(BlockChainTests) BOOST_AUTO_TEST_CASE(bcForkBlockTest) { - dev::test::executeTests("bcForkBlockTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests); + dev::test::executeTests("bcForkBlockTest", "/BlockchainTests",dev::test::getFolder(__FILE__) + "/BlockchainTestsFiller", dev::test::doBlockchainTests); } BOOST_AUTO_TEST_CASE(bcTotalDifficultyTest) { - dev::test::executeTests("bcTotalDifficultyTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests); + dev::test::executeTests("bcTotalDifficultyTest", "/BlockchainTests",dev::test::getFolder(__FILE__) + "/BlockchainTestsFiller", dev::test::doBlockchainTests); } BOOST_AUTO_TEST_CASE(bcInvalidRLPTest) { - dev::test::executeTests("bcInvalidRLPTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests); + dev::test::executeTests("bcInvalidRLPTest", "/BlockchainTests",dev::test::getFolder(__FILE__) + "/BlockchainTestsFiller", dev::test::doBlockchainTests); } BOOST_AUTO_TEST_CASE(bcRPC_API_Test) { - dev::test::executeTests("bcRPC_API_Test", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests); + dev::test::executeTests("bcRPC_API_Test", "/BlockchainTests",dev::test::getFolder(__FILE__) + "/BlockchainTestsFiller", dev::test::doBlockchainTests); } BOOST_AUTO_TEST_CASE(bcValidBlockTest) { - dev::test::executeTests("bcValidBlockTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests); + dev::test::executeTests("bcValidBlockTest", "/BlockchainTests",dev::test::getFolder(__FILE__) + "/BlockchainTestsFiller", dev::test::doBlockchainTests); } BOOST_AUTO_TEST_CASE(bcInvalidHeaderTest) { - dev::test::executeTests("bcInvalidHeaderTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests); + dev::test::executeTests("bcInvalidHeaderTest", "/BlockchainTests",dev::test::getFolder(__FILE__) + "/BlockchainTestsFiller", dev::test::doBlockchainTests); } BOOST_AUTO_TEST_CASE(bcUncleTest) { - dev::test::executeTests("bcUncleTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests); + dev::test::executeTests("bcUncleTest", "/BlockchainTests",dev::test::getFolder(__FILE__) + "/BlockchainTestsFiller", dev::test::doBlockchainTests); } BOOST_AUTO_TEST_CASE(bcUncleHeaderValiditiy) { - dev::test::executeTests("bcUncleHeaderValiditiy", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests); + dev::test::executeTests("bcUncleHeaderValiditiy", "/BlockchainTests",dev::test::getFolder(__FILE__) + "/BlockchainTestsFiller", dev::test::doBlockchainTests); } BOOST_AUTO_TEST_CASE(bcGasPricerTest) { - dev::test::executeTests("bcGasPricerTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests); + dev::test::executeTests("bcGasPricerTest", "/BlockchainTests",dev::test::getFolder(__FILE__) + "/BlockchainTestsFiller", dev::test::doBlockchainTests); } BOOST_AUTO_TEST_CASE(bcBruncleTest) { - dev::test::executeTests("bcBruncleTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests); + dev::test::executeTests("bcBruncleTest", "/BlockchainTests",dev::test::getFolder(__FILE__) + "/BlockchainTestsFiller", dev::test::doBlockchainTests); } BOOST_AUTO_TEST_CASE(bcWalletTest) { if (test::Options::get().wallet) - dev::test::executeTests("bcWalletTest", "/BlockTests",dev::test::getFolder(__FILE__) + "/BlockTestsFiller", dev::test::doBlockchainTests); + dev::test::executeTests("bcWalletTest", "/BlockchainTests",dev::test::getFolder(__FILE__) + "/BlockchainTestsFiller", dev::test::doBlockchainTests); } BOOST_AUTO_TEST_CASE(userDefinedFile) diff --git a/test/libethereum/gaspricer.cpp b/test/libethereum/gaspricer.cpp index 68a55ab42..105f4c2d7 100644 --- a/test/libethereum/gaspricer.cpp +++ b/test/libethereum/gaspricer.cpp @@ -90,51 +90,51 @@ BOOST_AUTO_TEST_CASE(basicGasPricerNoUpdate) BOOST_AUTO_TEST_CASE(basicGasPricer_RPC_API_Test) { - dev::test::executeGasPricerTest("RPC_API_Test", 30.679, 15.0, "/BlockTests/bcRPC_API_Test.json", TransactionPriority::Medium, 155632494086, 1); + dev::test::executeGasPricerTest("RPC_API_Test", 30.679, 15.0, "/BlockchainTests/bcRPC_API_Test.json", TransactionPriority::Medium, 155632494086, 1); } BOOST_AUTO_TEST_CASE(basicGasPricer_bcValidBlockTest) { - dev::test::executeGasPricerTest("SimpleTx", 30.679, 15.0, "/BlockTests/bcValidBlockTest.json", TransactionPriority::Medium, 155632494086, 10); + dev::test::executeGasPricerTest("SimpleTx", 30.679, 15.0, "/BlockchainTests/bcValidBlockTest.json", TransactionPriority::Medium, 155632494086, 10); } BOOST_AUTO_TEST_CASE(basicGasPricer_bcUncleTest) { - dev::test::executeGasPricerTest("twoUncle", 30.679, 15.0, "/BlockTests/bcUncleTest.json", TransactionPriority::Medium, 155632494086, 1); + dev::test::executeGasPricerTest("twoUncle", 30.679, 15.0, "/BlockchainTests/bcUncleTest.json", TransactionPriority::Medium, 155632494086, 1); } BOOST_AUTO_TEST_CASE(basicGasPricer_bcUncleHeaderValiditiy) { - dev::test::executeGasPricerTest("correct", 30.679, 15.0, "/BlockTests/bcUncleHeaderValiditiy.json", TransactionPriority::Medium, 155632494086, 1); + dev::test::executeGasPricerTest("correct", 30.679, 15.0, "/BlockchainTests/bcUncleHeaderValiditiy.json", TransactionPriority::Medium, 155632494086, 1); } BOOST_AUTO_TEST_CASE(basicGasPricer_notxs) { - dev::test::executeGasPricerTest("notxs", 30.679, 15.0, "/BlockTests/bcGasPricerTest.json", TransactionPriority::Medium, 155632494086, 155632494086); + dev::test::executeGasPricerTest("notxs", 30.679, 15.0, "/BlockchainTests/bcGasPricerTest.json", TransactionPriority::Medium, 155632494086, 155632494086); } BOOST_AUTO_TEST_CASE(basicGasPricer_highGasUsage_LowestPrio) { - dev::test::executeGasPricerTest("highGasUsage", 30.679, 15.0, "/BlockTests/bcGasPricerTest.json", TransactionPriority::Lowest, 15731282021, 10000000000000); + dev::test::executeGasPricerTest("highGasUsage", 30.679, 15.0, "/BlockchainTests/bcGasPricerTest.json", TransactionPriority::Lowest, 15731282021, 10000000000000); } BOOST_AUTO_TEST_CASE(basicGasPricer_highGasUsage_LowPrio) { - dev::test::executeGasPricerTest("highGasUsage", 30.679, 15.0, "/BlockTests/bcGasPricerTest.json", TransactionPriority::Low, 15731282021, 15734152261884); + dev::test::executeGasPricerTest("highGasUsage", 30.679, 15.0, "/BlockchainTests/bcGasPricerTest.json", TransactionPriority::Low, 15731282021, 15734152261884); } BOOST_AUTO_TEST_CASE(basicGasPricer_highGasUsage_MediumPrio) { - dev::test::executeGasPricerTest("highGasUsage", 30.679, 15.0, "/BlockTests/bcGasPricerTest.json", TransactionPriority::Medium, 15731282021, 20000000000000); + dev::test::executeGasPricerTest("highGasUsage", 30.679, 15.0, "/BlockchainTests/bcGasPricerTest.json", TransactionPriority::Medium, 15731282021, 20000000000000); } BOOST_AUTO_TEST_CASE(basicGasPricer_highGasUsage_HighPrio) { - dev::test::executeGasPricerTest("highGasUsage", 30.679, 15.0, "/BlockTests/bcGasPricerTest.json", TransactionPriority::High, 15731282021, 24265847738115); + dev::test::executeGasPricerTest("highGasUsage", 30.679, 15.0, "/BlockchainTests/bcGasPricerTest.json", TransactionPriority::High, 15731282021, 24265847738115); } BOOST_AUTO_TEST_CASE(basicGasPricer_highGasUsage_HighestPrio) { - dev::test::executeGasPricerTest("highGasUsage", 30.679, 15.0, "/BlockTests/bcGasPricerTest.json", TransactionPriority::Highest, 15731282021, 30000000000000); + dev::test::executeGasPricerTest("highGasUsage", 30.679, 15.0, "/BlockchainTests/bcGasPricerTest.json", TransactionPriority::Highest, 15731282021, 30000000000000); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/libethereum/state.cpp b/test/libethereum/state.cpp index 492bfb746..a134d024f 100644 --- a/test/libethereum/state.cpp +++ b/test/libethereum/state.cpp @@ -80,7 +80,7 @@ void doStateTests(json_spirit::mValue& v, bool _fillin) #if ETH_FATDB importer.exportTest(output, theState); #else - TBOOST_THROW_EXCEPTION(Exception() << errinfo_comment("You can not fill tests when FATDB is switched off")); + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("You can not fill tests when FATDB is switched off")); #endif } else diff --git a/test/libethereum/transaction.cpp b/test/libethereum/transaction.cpp index ad20331b3..b620fc5ec 100644 --- a/test/libethereum/transaction.cpp +++ b/test/libethereum/transaction.cpp @@ -50,7 +50,7 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin) { Transaction txFromFields(rlpStream.out(), CheckTransaction::Everything); if (!txFromFields.signature().isValid()) - TBOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); o["sender"] = toString(txFromFields.sender()); o["transaction"] = ImportTest::makeAllFieldsHex(tObj); @@ -94,7 +94,7 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin) RLP rlp(stream); txFromRlp = Transaction(rlp.data(), CheckTransaction::Everything); if (!txFromRlp.signature().isValid()) - TBOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); + BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); } catch(Exception const& _e) { diff --git a/test/libevm/vm.cpp b/test/libevm/vm.cpp index 25ed8113b..fdfb180fb 100644 --- a/test/libevm/vm.cpp +++ b/test/libevm/vm.cpp @@ -395,9 +395,9 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) { 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); + {TBOOST_CHECK_MESSAGE((o["out"].get_str() == o["expectOut"].get_str()), warning);} else - BOOST_WARN_MESSAGE((o["out"].get_str() == o["expectOut"].get_str()), warning); + TBOOST_WARN_MESSAGE((o["out"].get_str() == o["expectOut"].get_str()), warning); o.erase(o.find("expectOut")); } @@ -440,7 +440,7 @@ void doVMTests(json_spirit::mValue& v, bool _fillin) checkLog(fev.sub.logs, test.sub.logs); } else // Exception expected - BOOST_CHECK(vmExceptionOccured); + TBOOST_CHECK(vmExceptionOccured); } } } diff --git a/test/libp2p/capability.cpp b/test/libp2p/capability.cpp index 13ae4d498..e8c69655f 100644 --- a/test/libp2p/capability.cpp +++ b/test/libp2p/capability.cpp @@ -42,7 +42,7 @@ struct P2PFixture class TestCapability: public Capability { public: - TestCapability(Session* _s, HostCapabilityFace* _h, unsigned _idOffset, CapDesc const&): Capability(_s, _h, _idOffset), m_cntReceivedMessages(0), m_testSum(0) {} + TestCapability(std::shared_ptr _s, HostCapabilityFace* _h, unsigned _idOffset, CapDesc const&): Capability(_s, _h, _idOffset), m_cntReceivedMessages(0), m_testSum(0) {} virtual ~TestCapability() {} int countReceivedMessages() { return m_cntReceivedMessages; } int testSum() { return m_testSum; } diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index a839aa027..75793abf7 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -4355,6 +4355,267 @@ BOOST_AUTO_TEST_CASE(accessor_involving_strings) BOOST_REQUIRE(callContractFunction("data(uint256,uint256)", x, y) == result); } +BOOST_AUTO_TEST_CASE(bytes_in_function_calls) +{ + char const* sourceCode = R"( + contract Main { + string public s1; + string public s2; + function set(string _s1, uint x, string _s2) returns (uint) { + s1 = _s1; + s2 = _s2; + return x; + } + function setIndirectFromMemory(string _s1, uint x, string _s2) returns (uint) { + return this.set(_s1, x, _s2); + } + function setIndirectFromCalldata(string _s1, uint x, string _s2) external returns (uint) { + return this.set(_s1, x, _s2); + } + } + )"; + compileAndRun(sourceCode, 0, "Main"); + string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); + string s2("ABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVXYZ"); + vector lengthes{0, 31, 64, 65}; + for (auto l1: lengthes) + for (auto l2: lengthes) + { + bytes dyn1 = encodeArgs(u256(l1), s1.substr(0, l1)); + bytes dyn2 = encodeArgs(u256(l2), s2.substr(0, l2)); + bytes args1 = encodeArgs(u256(0x60), u256(l1), u256(0x60 + dyn1.size())) + dyn1 + dyn2; + BOOST_REQUIRE( + callContractFunction("setIndirectFromMemory(string,uint256,string)", asString(args1)) == + encodeArgs(u256(l1)) + ); + BOOST_CHECK(callContractFunction("s1()") == encodeArgs(0x20) + dyn1); + BOOST_CHECK(callContractFunction("s2()") == encodeArgs(0x20) + dyn2); + // swapped + bytes args2 = encodeArgs(u256(0x60), u256(l1), u256(0x60 + dyn2.size())) + dyn2 + dyn1; + BOOST_REQUIRE( + callContractFunction("setIndirectFromCalldata(string,uint256,string)", asString(args2)) == + encodeArgs(u256(l1)) + ); + BOOST_CHECK(callContractFunction("s1()") == encodeArgs(0x20) + dyn2); + BOOST_CHECK(callContractFunction("s2()") == encodeArgs(0x20) + dyn1); + } +} + +BOOST_AUTO_TEST_CASE(return_bytes_internal) +{ + char const* sourceCode = R"( + contract Main { + bytes s1; + function doSet(bytes _s1) returns (bytes _r1) { + s1 = _s1; + _r1 = s1; + } + function set(bytes _s1) external returns (uint _r, bytes _r1) { + _r1 = doSet(_s1); + _r = _r1.length; + } + } + )"; + compileAndRun(sourceCode, 0, "Main"); + string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); + vector lengthes{0, 31, 64, 65}; + for (auto l1: lengthes) + { + bytes dyn1 = encodeArgs(u256(l1), s1.substr(0, l1)); + bytes args1 = encodeArgs(u256(0x20)) + dyn1; + BOOST_REQUIRE( + callContractFunction("set(bytes)", asString(args1)) == + encodeArgs(u256(l1), u256(0x40)) + dyn1 + ); + } +} + +BOOST_AUTO_TEST_CASE(bytes_index_access_memory) +{ + char const* sourceCode = R"( + contract Main { + function f(bytes _s1, uint i1, uint i2, uint i3) returns (byte c1, byte c2, byte c3) { + c1 = _s1[i1]; + c2 = intern(_s1, i2); + c3 = internIndirect(_s1)[i3]; + } + function intern(bytes _s1, uint i) returns (byte c) { + return _s1[i]; + } + function internIndirect(bytes _s1) returns (bytes) { + return _s1; + } + } + )"; + compileAndRun(sourceCode, 0, "Main"); + string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); + bytes dyn1 = encodeArgs(u256(s1.length()), s1); + bytes args1 = encodeArgs(u256(0x80), u256(3), u256(4), u256(5)) + dyn1; + BOOST_REQUIRE( + callContractFunction("f(bytes,uint256,uint256,uint256)", asString(args1)) == + encodeArgs(string{s1[3]}, string{s1[4]}, string{s1[5]}) + ); +} + +BOOST_AUTO_TEST_CASE(bytes_in_constructors_unpacker) +{ + char const* sourceCode = R"( + contract Test { + uint public m_x; + bytes public m_s; + function Test(uint x, bytes s) { + m_x = x; + m_s = s; + } + } + )"; + string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); + bytes dyn1 = encodeArgs(u256(s1.length()), s1); + u256 x = 7; + bytes args1 = encodeArgs(x, u256(0x40)) + dyn1; + compileAndRun(sourceCode, 0, "Test", args1); + BOOST_REQUIRE(callContractFunction("m_x()") == encodeArgs(x)); + BOOST_REQUIRE(callContractFunction("m_s()") == encodeArgs(u256(0x20)) + dyn1); +} + +BOOST_AUTO_TEST_CASE(bytes_in_constructors_packer) +{ + char const* sourceCode = R"( + contract Base { + uint public m_x; + bytes m_s; + function Base(uint x, bytes s) { + m_x = x; + m_s = s; + } + function part(uint i) returns (byte) { + return m_s[i]; + } + } + contract Main is Base { + function Main(bytes s, uint x) Base(x, s){}//f(s)) {} + function f(bytes s) returns (bytes) { + return s; + } + } + contract Creator { + function f(uint x, bytes s) returns (uint r, byte ch) { + var c = new Main(s, x); + r = c.m_x(); + ch = c.part(x); + } + } + )"; + compileAndRun(sourceCode, 0, "Creator"); + string s1("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"); + bytes dyn1 = encodeArgs(u256(s1.length()), s1); + u256 x = 7; + bytes args1 = encodeArgs(x, u256(0x40)) + dyn1; + BOOST_REQUIRE( + callContractFunction("f(uint256,bytes)", asString(args1)) == + encodeArgs(x, string{s1[unsigned(x)]}) + ); +} + +BOOST_AUTO_TEST_CASE(arrays_from_and_to_storage) +{ + char const* sourceCode = R"( + contract Test { + uint24[] public data; + function set(uint24[] _data) returns (uint) { + data = _data; + return data.length; + } + function get() returns (uint24[]) { + return data; + } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + vector data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; + BOOST_REQUIRE( + callContractFunction("set(uint24[])", u256(0x20), u256(data.size()), data) == + encodeArgs(u256(data.size())) + ); + BOOST_CHECK(callContractFunction("data(uint256)", u256(7)) == encodeArgs(u256(8))); + BOOST_CHECK(callContractFunction("data(uint256)", u256(15)) == encodeArgs(u256(16))); + BOOST_CHECK(callContractFunction("data(uint256)", u256(18)) == encodeArgs()); + BOOST_CHECK(callContractFunction("get()") == encodeArgs(u256(0x20), u256(data.size()), data)); +} + +BOOST_AUTO_TEST_CASE(arrays_complex_from_and_to_storage) +{ + char const* sourceCode = R"( + contract Test { + uint24[3][] public data; + function set(uint24[3][] _data) returns (uint) { + data = _data; + return data.length; + } + function get() returns (uint24[3][]) { + return data; + } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + vector data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; + BOOST_REQUIRE( + callContractFunction("set(uint24[3][])", u256(0x20), u256(data.size() / 3), data) == + encodeArgs(u256(data.size() / 3)) + ); + BOOST_CHECK(callContractFunction("data(uint256,uint256)", u256(2), u256(2)) == encodeArgs(u256(9))); + BOOST_CHECK(callContractFunction("data(uint256,uint256)", u256(5), u256(1)) == encodeArgs(u256(17))); + BOOST_CHECK(callContractFunction("data(uint256,uint256)", u256(6), u256(0)) == encodeArgs()); + BOOST_CHECK(callContractFunction("get()") == encodeArgs(u256(0x20), u256(data.size() / 3), data)); +} + +BOOST_AUTO_TEST_CASE(arrays_complex_memory_index_access) +{ + char const* sourceCode = R"( + contract Test { + function set(uint24[3][] _data, uint a, uint b) returns (uint l, uint e) { + l = _data.length; + e = _data[a][b]; + } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + vector data{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}; + BOOST_REQUIRE(callContractFunction( + "set(uint24[3][],uint256,uint256)", + u256(0x60), + u256(3), + u256(2), + u256(data.size() / 3), + data + ) == encodeArgs(u256(data.size() / 3), u256(data[3 * 3 + 2]))); +} + +BOOST_AUTO_TEST_CASE(bytes_memory_index_access) +{ + char const* sourceCode = R"( + contract Test { + function set(bytes _data, uint i) returns (uint l, byte c) { + l = _data.length; + c = _data[i]; + } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + string data("abcdefgh"); + BOOST_REQUIRE(callContractFunction( + "set(bytes,uint256)", + u256(0x40), + u256(3), + u256(data.size()), + data + ) == encodeArgs(u256(data.size()), string("d"))); +} + BOOST_AUTO_TEST_CASE(storage_array_ref) { char const* sourceCode = R"( @@ -4408,6 +4669,28 @@ BOOST_AUTO_TEST_CASE(storage_array_ref) BOOST_CHECK(callContractFunction("find(uint256)", u256(400)) == encodeArgs(u256(-1))); } +BOOST_AUTO_TEST_CASE(memory_types_initialisation) +{ + char const* sourceCode = R"( + contract Test { + mapping(uint=>uint) data; + function stat() returns (uint[5]) + { + data[2] = 3; // make sure to use some memory + } + function dyn() returns (uint[]) { stat(); } + function nested() returns (uint[3][]) { stat(); } + function nestedStat() returns (uint[3][7]) { stat(); } + } + )"; + compileAndRun(sourceCode, 0, "Test"); + + BOOST_CHECK(callContractFunction("stat()") == encodeArgs(vector(5))); + BOOST_CHECK(callContractFunction("dyn()") == encodeArgs(u256(0x20), u256(0))); + BOOST_CHECK(callContractFunction("nested()") == encodeArgs(u256(0x20), u256(0))); + BOOST_CHECK(callContractFunction("nestedStat()") == encodeArgs(vector(3 * 7))); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index afa8b727f..765593c59 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -1987,6 +1987,19 @@ BOOST_AUTO_TEST_CASE(mem_array_assignment_changes_base_type) BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); } +BOOST_AUTO_TEST_CASE(dynamic_return_types_not_possible) +{ + char const* sourceCode = R"( + contract C { + function f(uint) returns (string); + function g() { + var x = this.f(2); + } + } + )"; + BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); +} + BOOST_AUTO_TEST_SUITE_END() } diff --git a/test/libsolidity/solidityExecutionFramework.h b/test/libsolidity/solidityExecutionFramework.h index 0079d82b6..200940a43 100644 --- a/test/libsolidity/solidityExecutionFramework.h +++ b/test/libsolidity/solidityExecutionFramework.h @@ -127,6 +127,14 @@ public: return _padLeft ? padding + _value : _value + padding; } static bytes encode(std::string const& _value) { return encode(asBytes(_value), false); } + template + static bytes encode(std::vector<_T> const& _value) + { + bytes ret; + for (auto const& v: _value) + ret += encode(v); + return ret; + } template static bytes encodeArgs(FirstArg const& _firstArg, Args const&... _followingArgs) diff --git a/test/libwhisper/bloomFilter.cpp b/test/libwhisper/bloomFilter.cpp index 799c4caf6..e49473bdc 100644 --- a/test/libwhisper/bloomFilter.cpp +++ b/test/libwhisper/bloomFilter.cpp @@ -27,35 +27,39 @@ using namespace std; using namespace dev; using namespace dev::shh; -void testAddNonExisting(TopicBloomFilter& _f, AbridgedTopic const& _h) +using TopicBloomFilterShort = TopicBloomFilterBase<4>; +using TopicBloomFilterLong = TopicBloomFilterBase<8>; +using TopicBloomFilterTest = TopicBloomFilterLong; + +void testAddNonExisting(TopicBloomFilterShort& _f, AbridgedTopic const& _h) { BOOST_REQUIRE(!_f.containsRaw(_h)); _f.addRaw(_h); BOOST_REQUIRE(_f.containsRaw(_h)); } -void testRemoveExisting(TopicBloomFilter& _f, AbridgedTopic const& _h) +void testRemoveExisting(TopicBloomFilterShort& _f, AbridgedTopic const& _h) { BOOST_REQUIRE(_f.containsRaw(_h)); _f.removeRaw(_h); BOOST_REQUIRE(!_f.containsRaw(_h)); } -void testAddNonExistingBloom(TopicBloomFilter& _f, AbridgedTopic const& _h) +void testAddNonExistingBloom(TopicBloomFilterShort& _f, AbridgedTopic const& _h) { BOOST_REQUIRE(!_f.containsBloom(_h)); _f.addBloom(_h); BOOST_REQUIRE(_f.containsBloom(_h)); } -void testRemoveExistingBloom(TopicBloomFilter& _f, AbridgedTopic const& _h) +void testRemoveExistingBloom(TopicBloomFilterShort& _f, AbridgedTopic const& _h) { BOOST_REQUIRE(_f.containsBloom(_h)); _f.removeBloom(_h); BOOST_REQUIRE(!_f.containsBloom(_h)); } -int calculateExpected(TopicBloomFilter const& f, int const n) +int calculateExpected(TopicBloomFilterTest const& f, int const n) { int const m = f.size * 8; // number of bits in the bloom int const k = f.BitsPerBloom; // number of hash functions (e.g. bits set to 1 in every bloom) @@ -76,7 +80,7 @@ int calculateExpected(TopicBloomFilter const& f, int const n) return static_cast(kBitsSet * 100 + 0.5); // in percents, rounded up } -void testFalsePositiveRate(TopicBloomFilter const& f, int const inserted, Topic& x) +void testFalsePositiveRate(TopicBloomFilterTest const& f, int const inserted, Topic& x) { int const c_sampleSize = 1000; int falsePositive = 0; @@ -104,8 +108,8 @@ BOOST_AUTO_TEST_CASE(falsePositiveRate) VerbosityHolder setTemporaryLevel(10); cnote << "Testing Bloom Filter False Positive Rate..."; - TopicBloomFilter f; - Topic x(0xABCDEF); // deterministic pseudorandom value + TopicBloomFilterTest f; + Topic x(0xC0DEFEED); // deterministic pseudorandom value for (int i = 1; i < 21; ++i) { @@ -120,7 +124,7 @@ BOOST_AUTO_TEST_CASE(bloomFilterRandom) VerbosityHolder setTemporaryLevel(10); cnote << "Testing Bloom Filter matching..."; - TopicBloomFilter f; + TopicBloomFilterShort f; vector vec; Topic x(0xDEADBEEF); int const c_rounds = 4; @@ -146,7 +150,7 @@ BOOST_AUTO_TEST_CASE(bloomFilterRaw) VerbosityHolder setTemporaryLevel(10); cnote << "Testing Raw Bloom matching..."; - TopicBloomFilter f; + TopicBloomFilterShort f; AbridgedTopic b00000001(0x01); AbridgedTopic b00010000(0x10);